Merging the openflow part to the nepi-3-dev branch
authorJulien Tribino <julien.tribino@inria.fr>
Mon, 19 May 2014 15:13:24 +0000 (17:13 +0200)
committerJulien Tribino <julien.tribino@inria.fr>
Mon, 19 May 2014 15:13:24 +0000 (17:13 +0200)
206 files changed:
examples/linux/ccn/ccncat_2_nodes.py
examples/linux/ccn/two_nodes_file_retrieval.py [changed mode: 0644->0755]
examples/linux/ns3/ping.py [new file with mode: 0644]
examples/linux/ping.py
examples/planetlab/ccn/two_nodes_file_retrieval.py
examples/planetlab/openvswitch/ovs_ping_exp.py [new file with mode: 0644]
examples/planetlab/ping_experiment.py
examples/planetlab/ping_filters_experiment.py [new file with mode: 0755]
examples/planetlab/ping_sfa.py [new file with mode: 0755]
setup.py
src/nepi/execution/attribute.py
src/nepi/execution/ec.py
src/nepi/execution/resource.py
src/nepi/resources/all/collector.py
src/nepi/resources/linux/application.py
src/nepi/resources/linux/ccn/ccnapplication.py
src/nepi/resources/linux/ccn/ccncontent.py
src/nepi/resources/linux/ccn/ccnd.py
src/nepi/resources/linux/ccn/ccnping.py
src/nepi/resources/linux/ccn/ccnpingserver.py
src/nepi/resources/linux/ccn/ccnr.py
src/nepi/resources/linux/ccn/fibentry.py
src/nepi/resources/linux/interface.py
src/nepi/resources/linux/mtr.py
src/nepi/resources/linux/node.py
src/nepi/resources/linux/nping.py
src/nepi/resources/linux/ns3/__init__.py [new file with mode: 0644]
src/nepi/resources/linux/ns3/dependencies/pygccxml-1.0.0.tar.gz [new file with mode: 0644]
src/nepi/resources/linux/ns3/ns3client.py [new file with mode: 0644]
src/nepi/resources/linux/ns3/ns3dceapplication.py [new file with mode: 0644]
src/nepi/resources/linux/ns3/ns3simulation.py [new file with mode: 0644]
src/nepi/resources/linux/ping.py
src/nepi/resources/linux/tcpdump.py
src/nepi/resources/linux/traceroute.py
src/nepi/resources/linux/udptest.py
src/nepi/resources/linux/udptunnel.py
src/nepi/resources/ns3/classes/__init__.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/aarf_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/aarfcd_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/adhoc_wifi_mac.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/aloha_noack_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/amrr_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/ap_wifi_mac.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/arf_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/arp_l3protocol.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/base_station_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/bridge_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/bridge_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/bulk_send_application.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/burst_error_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/cara_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/constant_acceleration_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/constant_position_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/constant_rate_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/constant_velocity_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/cost231propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/csma_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/csma_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/dce_application.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/drop_tail_queue.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/dsrdsr_routing.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/emu_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/error_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/error_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/fd_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/fixed_rss_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/friis_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/gauss_markov_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/hierarchical_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/icmpv4l4protocol.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/icmpv6l4protocol.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/ideal_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/ipv4l3protocol.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/jakes_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/list_error_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/log_distance_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/loopback_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/lte_enb_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/lte_simple_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/matrix_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/mesh_point_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/mesh_wifi_interface_mac.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/minstrel_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/multi_model_spectrum_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/nakagami_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/nist_error_rate_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/node.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/non_communicating_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/on_off_application.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/onoe_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/packet_sink.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/ping6.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/point_to_point_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/point_to_point_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/point_to_point_remote_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/radvd.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/random_direction2d_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/random_propagation_delay_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/random_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/random_walk2d_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/random_waypoint_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/range_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/rate_error_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/receive_list_error_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/red_queue.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/rraa_wifi_manager.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/simple_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/simple_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/single_model_spectrum_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/sta_wifi_mac.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/subscriber_station_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/tap_bridge.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/tcp_l4protocol.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/uan_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/udp_client.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/udp_echo_client.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/udp_echo_server.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/udp_l4protocol.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/udp_server.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/udp_trace_client.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/v4ping.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/virtual_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/waypoint_mobility_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/wifi_net_device.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/yans_error_rate_model.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/yans_wifi_channel.py [new file with mode: 0644]
src/nepi/resources/ns3/classes/yans_wifi_phy.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3application.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3arpl3protocol.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3base.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3channel.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3client.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3dceapplication.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3errormodel.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3errorratemodel.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3icmpv4l4protocol.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3ipv4l3protocol.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3mobilitymodel.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3netdevice.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3node.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3propagationdelaymodel.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3propagationlossmodel.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3queue.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3route.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3server.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3simulation.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3wifichannel.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3wifimac.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3wifinetdevice.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3wifiphy.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3wifiremotestationmanager.py [new file with mode: 0644]
src/nepi/resources/ns3/ns3wrapper.py
src/nepi/resources/ns3/ns3wrapper_server.py [deleted file]
src/nepi/resources/ns3/resource_manager_generator.py [new file with mode: 0644]
src/nepi/resources/ns3/templates/attribute_template.txt [new file with mode: 0644]
src/nepi/resources/ns3/templates/resource_manager_template.txt [new file with mode: 0644]
src/nepi/resources/ns3/templates/trace_template.txt [new file with mode: 0644]
src/nepi/resources/omf/application.py
src/nepi/resources/omf/interface.py
src/nepi/resources/omf/omf_api.py
src/nepi/resources/omf/omf_client.py
src/nepi/resources/planetlab/node.py
src/nepi/resources/planetlab/openvswitch/ovs.py
src/nepi/resources/planetlab/openvswitch/ovsport.py
src/nepi/resources/planetlab/openvswitch/tunnel.py
src/nepi/resources/planetlab/plcapi.py
src/nepi/resources/planetlab/sfa_node.py [new file with mode: 0644]
src/nepi/resources/planetlab/tap.py
src/nepi/resources/planetlab/vroute.py
src/nepi/util/execfuncs.py
src/nepi/util/logger.py
src/nepi/util/manifoldapi.py
src/nepi/util/parser.py
src/nepi/util/sfa_api.py [deleted file]
src/nepi/util/sfa_sfav1.py [deleted file]
src/nepi/util/sfaapi.py [new file with mode: 0644]
src/nepi/util/sfarspec_proc.py [new file with mode: 0644]
src/nepi/util/sshfuncs.py
src/nepi/util/timefuncs.py
test/lib/test_utils.py
test/resources/linux/application.py
test/resources/linux/ccn/ccnping.py
test/resources/linux/ccn/fibentry.py
test/resources/linux/interface.py
test/resources/linux/mtr.py
test/resources/linux/node.py
test/resources/linux/nping.py
test/resources/linux/ns3/ns-3.18-user.tar.gz [new file with mode: 0644]
test/resources/linux/ns3/ns3client.py [new file with mode: 0644]
test/resources/linux/ns3/ns3dceapplication.py [new file with mode: 0644]
test/resources/linux/ns3/ns3simulation.py [new file with mode: 0644]
test/resources/linux/ns3/repoFile1 [new file with mode: 0644]
test/resources/linux/ping.py
test/resources/linux/tcpdump.py
test/resources/linux/traceroute.py
test/resources/linux/udptest.py
test/resources/ns3/ns3wrapper.py
test/resources/planetlab/sfa_node.py [new file with mode: 0755]
test/util/sshfuncs.py
test/util/timefuncs.py [new file with mode: 0755]

index 2e0af0e..34d3350 100755 (executable)
@@ -43,6 +43,7 @@ from nepi.resources.linux.node import OSType
 
 from optparse import OptionParser, SUPPRESS_HELP
 
+import getpass
 import os
 import time
 
@@ -151,7 +152,8 @@ def get_options():
     #       the host can be accessed through SSH without prompting
     #       for a password. The host must allow X forwarding using SSH.
     linux_host = 'roseval.pl.sophia.inria.fr'
-
+    linux_user = getpass.getuser()
+    
     usage = "usage: %prog -p <pl-host> -s <pl-slice> -l <linux-host> -u <linux-user> -m <movie> -e <exp-id> -i <ssh_key>"
 
     parser = OptionParser(usage=usage)
@@ -164,8 +166,8 @@ def get_options():
             help="Hostname of second Linux host (non PlanetLab)",
             default = linux_host, type="str")
     parser.add_option("-u", "--linux-user", dest="linux_user", 
-            help="User for extra Linux host (non PlanetLab)", default = linux_host,
-            type="str")
+            help="User for extra Linux host (non PlanetLab)", 
+            default = linux_user, type="str")
     parser.add_option("-m", "--movie", dest="movie", 
             help="Stream movie", type="str")
     parser.add_option("-e", "--exp-id", dest="exp_id", 
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/examples/linux/ns3/ping.py b/examples/linux/ns3/ping.py
new file mode 100644 (file)
index 0000000..041771e
--- /dev/null
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.ec import ExperimentController 
+from nepi.execution.trace import TraceAttr
+
+ec = ExperimentController(exp_id = "ns3-p2p-ping")
+
+# Simulation will run in the local machine
+node = ec.register_resource("LinuxNode")
+ec.set(node, "hostname", "localhost")
+
+# Add a simulation resource
+simu = ec.register_resource("LinuxNS3Simulation")
+ec.set(simu, "verbose", True)
+ec.register_connection(simu, node)
+
+## Add a ns-3 node with its protocol stack
+nsnode1 = ec.register_resource("ns3::Node")
+ec.register_connection(nsnode1, simu)
+
+ipv4 = ec.register_resource("ns3::Ipv4L3Protocol")
+ec.register_connection(nsnode1, ipv4)
+arp = ec.register_resource("ns3::ArpL3Protocol")
+ec.register_connection(nsnode1, arp)
+icmp = ec.register_resource("ns3::Icmpv4L4Protocol")
+ec.register_connection(nsnode1, icmp)
+
+# Add a point to point net device to the node
+dev1 = ec.register_resource("ns3::PointToPointNetDevice")
+ec.set(dev1, "ip", "10.0.0.1")
+ec.set(dev1, "prefix", "30")
+ec.register_connection(nsnode1, dev1)
+queue1 = ec.register_resource("ns3::DropTailQueue")
+ec.register_connection(dev1, queue1)
+
+## Add another ns-3 node with its protocol stack
+nsnode2 = ec.register_resource("ns3::Node")
+ec.register_connection(nsnode2, simu)
+
+ipv4 = ec.register_resource("ns3::Ipv4L3Protocol")
+ec.register_connection(nsnode2, ipv4)
+arp = ec.register_resource("ns3::ArpL3Protocol")
+ec.register_connection(nsnode2, arp)
+icmp = ec.register_resource("ns3::Icmpv4L4Protocol")
+ec.register_connection(nsnode2, icmp)
+
+# Add a point to point net device to the node
+dev2 = ec.register_resource("ns3::PointToPointNetDevice")
+ec.set(dev2, "ip", "10.0.0.2")
+ec.set(dev2, "prefix", "30")
+ec.register_connection(nsnode2, dev2)
+queue2 = ec.register_resource("ns3::DropTailQueue")
+ec.register_connection(dev2, queue2)
+
+# Add a point to point channel
+chan = ec.register_resource("ns3::PointToPointChannel")
+ec.set(chan, "Delay", "0s")
+ec.register_connection(chan, dev1)
+ec.register_connection(chan, dev2)
+
+### create pinger
+ping = ec.register_resource("ns3::V4Ping")
+ec.set (ping, "Remote", "10.0.0.2")
+ec.set (ping, "Interval", "1s")
+ec.set (ping, "Verbose", True)
+ec.set (ping, "StartTime", "0s")
+ec.set (ping, "StopTime", "20s")
+ec.register_connection(ping, nsnode1)
+
+ec.deploy()
+
+ec.wait_finished([ping])
+
+stdout = ec.trace(simu, "stdout") 
+
+ec.shutdown()
+
+print "PING OUTPUT", stdout
index aa80364..6b5a249 100644 (file)
@@ -22,9 +22,12 @@ from nepi.execution.ec import ExperimentController
 
 ec = ExperimentController(exp_id = "ping-exp")
         
+hostname = ## Add a string with the target hostname
+username = ## Add a string with the username to SSH hostname
+
 node = ec.register_resource("LinuxNode")
-ec.set(node, "hostname", "planetlab2.cs.aueb.gr")
-ec.set(node, "username", "inria_pres")
+ec.set(node, "hostname", hostname)
+ec.set(node, "username", username)
 ec.set(node, "cleanHome", True)
 ec.set(node, "cleanProcesses", True)
 
@@ -38,5 +41,4 @@ ec.wait_finished(app)
 
 print ec.trace(app, "stdout")
 
-
 ec.shutdown()
index 7da5d17..096268f 100644 (file)
@@ -71,7 +71,7 @@ ec.set(node2, "plpassword", pl_pass)
 # username should be your PlanetLab slice name 
 ec.set(node2, "username", slicename)
 # Absolute path to the SSH private key for PlanetLab
-ec.set(node1, "identity", pl_ssh_key)
+ec.set(node2, "identity", pl_ssh_key)
 # Clean all files, results, etc, from previous experiments wit the same exp_id
 ec.set(node2, "cleanExperiment", True)
 # Kill all running processes in the PlanetLab node before running the experiment
diff --git a/examples/planetlab/openvswitch/ovs_ping_exp.py b/examples/planetlab/openvswitch/ovs_ping_exp.py
new file mode 100644 (file)
index 0000000..18c2f15
--- /dev/null
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+#         Alexandros Kouvakas <alexandros.kouvakas@gmail.com>
+#
+#         Switch1 ------- Switch2         
+#            /                \           
+#           /                  \          
+#          /                    \         
+#       Host1                  Host2      
+
+
+
+from nepi.execution.ec import ExperimentController
+import os, time
+
+def add_node(ec, host, user, pl_user, pl_password):
+    node = ec.register_resource("PlanetlabNode")
+    ec.set(node, "hostname", host)
+    ec.set(node, "username", user)
+    if pl_user:
+        ec.set(node, "pluser", pl_user)
+    if pl_password:
+        ec.set(node, "plpassword", pl_password)
+    ec.set(node, "cleanHome", True)
+    ec.set(node, "cleanProcesses", True)
+
+    return node
+
+def add_ovs(ec, bridge_name, virtual_ip_pref, controller_ip, controller_port, node):
+    ovs = ec.register_resource("OVSWitch")
+    ec.set(ovs, "bridge_name", bridge_name)
+    ec.set(ovs, "virtual_ip_pref", virtual_ip_pref)
+    ec.set(ovs, "controller_ip", controller_ip)
+    ec.set(ovs, "controller_port", controller_port)
+    ec.register_connection(ovs, node)
+    return ovs
+
+def add_port(ec, port_name, ovs):
+    port = ec.register_resource("OVSPort")
+    ec.set(port, "port_name", port_name)
+    ec.register_connection(port, ovs)
+    return port
+
+def add_tap(ec, ip4, prefix4, pointopoint, node):
+    tap = ec.register_resource("PlanetlabTap")
+    ec.set(tap, "ip4", ip4)
+    ec.set(tap, "prefix4", prefix4)
+    ec.set(tap, "pointopoint", pointopoint)
+    ec.set(tap, "up", True)
+    ec.register_connection(tap, node)
+    return tap
+
+def add_tunnel(ec, network, port0, tap):
+    tunnel = ec.register_resource("OVSTunnel")
+    ec.set(tunnel, "network", network)
+    ec.register_connection(port0, tunnel)
+    ec.register_connection(tunnel, tap)
+    return tunnel
+
+def add_app(ec, command, node):
+    app = ec.register_resource("LinuxApplication")
+    ec.set(app, "command", command)
+    ec.register_connection(app, node)
+    return app
+
+# Create the EC
+ec = ExperimentController(exp_id = "test")
+
+switch1 = "planetlab2.virtues.fi"
+switch2 = "planetlab2.upc.es"
+host1 = "planetlab2.ionio.gr"
+host2 = "iraplab2.iralab.uni-karlsruhe.de"
+
+network = "192.168.3.0"
+
+slicename = "inria_nepi"
+
+pl_user = os.environ.get("PL_USER")
+pl_password = os.environ.get("PL_PASS")
+
+s1_node = add_node(ec, switch1, slicename, pl_user, pl_password)
+s2_node = add_node(ec, switch2, slicename, pl_user, pl_password)
+
+# Add switches 
+ovs1 = add_ovs(ec, "nepi_bridge", "192.168.3.1/24", "85.23.168.77", "6633", s1_node)
+ovs2 = add_ovs(ec, "nepi_bridge", "192.168.3.2/24", "85.23.168.77", "6633", s2_node)
+
+# Add ports on ovs
+port1 = add_port(ec, "nepi_port1", ovs1)
+port3 = add_port(ec, "nepi_port3", ovs1)
+port2 = add_port(ec, "nepi_port2", ovs2)
+port4 = add_port(ec, "nepi_port4", ovs2)
+
+h1_node = add_node(ec, host1, slicename, pl_user, pl_password)
+h2_node = add_node(ec, host2, slicename, pl_user, pl_password)
+
+# Add tap devices
+tap1 = add_tap(ec, "192.168.3.3", 24, "192.168.3.1", h1_node)
+tap2 = add_tap(ec, "192.168.3.4", 24, "192.168.3.2", h2_node)
+
+# Connect the nodes
+tunnel1 = add_tunnel(ec, network, port1, tap1)
+tunnel2 = add_tunnel(ec, network, port2, tap2)
+tunnel3 = add_tunnel(ec, network, port3, port4)
+
+# Add ping commands
+app1 = add_app(ec, "ping -c5 192.168.3.2", s1_node)
+app2 = add_app(ec, "ping -c5 192.168.3.3", s1_node)
+app3 = add_app(ec, "ping -c5 192.168.3.4", s1_node)
+app4 = add_app(ec, "ping -c5 192.168.3.1", s2_node)
+app5 = add_app(ec, "ping -c5 192.168.3.3", s2_node)
+app6 = add_app(ec, "ping -c5 192.168.3.4", s2_node)
+app7 = add_app(ec, "ping -c5 192.168.3.1", h1_node)
+app8 = add_app(ec, "ping -c5 192.168.3.2", h1_node)
+app9 = add_app(ec, "ping -c5 192.168.3.4", h1_node)
+app10 = add_app(ec, "ping -c5 192.168.3.1", h2_node)
+app11 = add_app(ec, "ping -c5 192.168.3.2", h2_node)
+app12 = add_app(ec, "ping -c5 192.168.3.3", h2_node)
+
+ec.deploy()
+
+ec.wait_finished([app1, app2, app3, app4, app5, app6, app7, app8, app9, app10, app11, app12])
+
+# Retreive ping results and save
+# them in a file
+ping1 = ec.trace(app1, 'stdout')
+ping2 = ec.trace(app2, 'stdout')
+ping3 = ec.trace(app3, 'stdout')
+ping4 = ec.trace(app4, 'stdout')
+ping5 = ec.trace(app5, 'stdout')
+ping6 = ec.trace(app6, 'stdout')
+ping7 = ec.trace(app7, 'stdout')
+ping8 = ec.trace(app8, 'stdout')
+ping9 = ec.trace(app9, 'stdout')
+ping10 = ec.trace(app10, 'stdout')
+ping11 = ec.trace(app11, 'stdout')
+ping12 = ec.trace(app12, 'stdout')
+
+
+f = open("examples/openvswitch/ping_res.txt", 'w')
+
+if not ping12:
+  ec.shutdown()
+
+f.write(ping1)
+f.write(ping2)
+f.write(ping3)
+f.write(ping4)
+f.write(ping5)
+f.write(ping6)
+f.write(ping7)
+f.write(ping8)
+f.write(ping9)
+f.write(ping10)
+f.write(ping11)
+f.write(ping12)
+f.close()
+
+# Delete the overlay network
+ec.shutdown()
+
+
+
+
+
index 3576579..4a693fd 100755 (executable)
@@ -23,53 +23,6 @@ from nepi.execution.resource import ResourceAction, ResourceState
 
 import os
 
-def create_node(ec, username, pl_user, pl_password, hostname=None, country=None,
-                operatingSystem=None, minBandwidth=None, minCpu=None):
-
-    node = ec.register_resource("PlanetlabNode")
-
-    if username:
-        ec.set(node, "username", username)
-    if pl_user:
-        ec.set(node, "pluser", pl_user)
-    if pl_password:
-        ec.set(node, "plpassword", pl_password)
-
-    if hostname:
-        ec.set(node, "hostname", hostname)
-    if country:
-        ec.set(node, "country", country)
-    if operatingSystem:
-        ec.set(node, "operatingSystem", operatingSystem)
-    if minBandwidth:
-        ec.set(node, "minBandwidth", minBandwidth)
-    if minCpu:
-        ec.set(node, "minCpu", minCpu)
-
-    ec.set(node, "cleanHome", True)
-    ec.set(node, "cleanProcesses", True)
-    
-    return node
-
-def add_app(ec, command, node, sudo=None, video=None, depends=None, forward_x11=None, \
-        env=None):
-    app = ec.register_resource("LinuxApplication")
-    if sudo is not None:
-        ec.set(app, "sudo", sudo)
-    if video is not None:
-        ec.set(app, "sources", video)
-    if depends is not None:
-        ec.set(app, "depends", depends)
-    if forward_x11 is not None:
-        ec.set(app, "forwardX11", forward_x11)
-    if env is not None:
-        ec.set(app, "env", env)
-    ec.set(app, "command", command)
-
-    ec.register_connection(app, node)
-
-    return app
-
 exp_id = "ping_exp"
 
 # Create the entity Experiment Controller:
@@ -86,74 +39,35 @@ username = "inria_sfatest"
 pl_user = "lucia.guevgeozian_odizzio@inria.fr"
 pl_password =  os.environ.get("PL_PASS")
 
-# Choose the PlanetLab nodes for the experiment, in this example 5 nodes are
-# used, and they are picked according to different criterias.
-
-# First node will be the one defined by its hostname.
-hostname = "planetlab2.utt.fr"
-node1 = create_node(ec, username, pl_user, pl_password, hostname=hostname)
-
-# Second node will be any node in France.
-country = "France"
-node2 = create_node(ec, username, pl_user, pl_password, country=country)
-
-# Third node will be a node in France that has Fedora 14 installed.
-operatingSystem = "f14"
-node3 = create_node(ec, username, pl_user, pl_password, country=country,
-                operatingSystem=operatingSystem)
-
-# Forth node will have at least 50% of CPU available
-minCpu=50
-node4 = create_node(ec, username, pl_user, pl_password, minCpu=minCpu)
-
-# Fifth node can be any node, constrains are not important.
-node5 = create_node(ec, username, pl_user, pl_password)
-
-# Register the applications to run in the nodes, in this case just ping to the 
-# first node:
-apps_per_node = dict()
-apps = []
-for node in [node2, node3, node4, node5]:
-    command = "ping -c5 %s > ping%s.txt" % (hostname, node)
-    app = add_app(ec, command, node)
-    apps_per_node[node] = app
-    apps.append(app)
-
-# Register conditions
+# Define a Planetlab Node with no restriction, it can be any node
+node = ec.register_resource('PlanetlabNode')
+ec.set(node, "username", username)
+ec.set(node, "pluser", pl_user)
+ec.set(node, "plpassword", pl_password)
+ec.set(node, "cleanHome", True)
+ec.set(node, "cleanProcesses", True)
 
-# The nodes that are completely identified by their hostnames have to be provisioned 
-# before the rest of the nodes. This assures that no other resource will use the
-# identified node even if the constraints matchs. 
-# In this example node2, node3, node4 and node5, are deployed after node1 is 
-# provisioned. node1 must be the node planetlab2.utt.fr, meanwhile node2, node3,
-# node4 and node5 just need to fulfill certain constraints.
-# Applications are always deployed after nodes, so no need to register conditions
-# for the apps in this example.
+# Define a ping application
+app = ec.register_resource('LinuxApplication')
+ec.set(app, 'command', 'ping -c5 google.com > ping_google.txt')
 
-ec.register_condition(node2, ResourceAction.DEPLOY, node1, ResourceState.PROVISIONED)
-ec.register_condition(node3, ResourceAction.DEPLOY, node1, ResourceState.PROVISIONED)
-ec.register_condition(node4, ResourceAction.DEPLOY, node1, ResourceState.PROVISIONED)
-ec.register_condition(node5, ResourceAction.DEPLOY, node1, ResourceState.PROVISIONED)
+# Connect the application to the node
+ec.register_connection(node, app)
     
 # Deploy the experiment:
 ec.deploy()
 
-# Wait until the applications are finish to retrive the traces:
-ec.wait_finished(apps)
+# Wait until the application is finish to retrive the trace:
+ec.wait_finished(app)
 
-traces = dict() 
-for node, app in apps_per_node.iteritems():
-    ping_string = "ping%s.txt" % node
-    trace = ec.trace(app, ping_string)
-    traces[node]= trace
+trace = ec.trace(app, 'ping_google.txt')
 
 # Choose a directory to store the traces locally, change to a convenient path for you:
 directory = "examples/planetlab/"
-for node, trace in traces.iteritems():
-    trace_file = directory + "ping%s.txt" % node
-    f = open(trace_file, "w")
-    f.write(trace)
-    f.close()
+trace_file = directory + "ping_google.txt"
+f = open(trace_file, "w")
+f.write(trace)
+f.close()
 
 # Do the experiment controller shutdown:
 ec.shutdown()
diff --git a/examples/planetlab/ping_filters_experiment.py b/examples/planetlab/ping_filters_experiment.py
new file mode 100755 (executable)
index 0000000..79d4738
--- /dev/null
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
+
+from nepi.execution.ec import ExperimentController
+from nepi.execution.resource import ResourceAction, ResourceState
+
+import os
+
+def create_node(ec, username, pl_user, pl_password, hostname=None, country=None,
+                operatingSystem=None, minBandwidth=None, minCpu=None):
+
+    node = ec.register_resource("PlanetlabNode")
+
+    if username:
+        ec.set(node, "username", username)
+    if pl_user:
+        ec.set(node, "pluser", pl_user)
+    if pl_password:
+        ec.set(node, "plpassword", pl_password)
+
+    if hostname:
+        ec.set(node, "hostname", hostname)
+    if country:
+        ec.set(node, "country", country)
+    if operatingSystem:
+        ec.set(node, "operatingSystem", operatingSystem)
+    if minBandwidth:
+        ec.set(node, "minBandwidth", minBandwidth)
+    if minCpu:
+        ec.set(node, "minCpu", minCpu)
+
+    ec.set(node, "cleanHome", True)
+    ec.set(node, "cleanProcesses", True)
+    
+    return node
+
+def add_app(ec, command, node, sudo=None, video=None, depends=None, forward_x11=None, \
+        env=None):
+    app = ec.register_resource("LinuxApplication")
+    if sudo is not None:
+        ec.set(app, "sudo", sudo)
+    if video is not None:
+        ec.set(app, "sources", video)
+    if depends is not None:
+        ec.set(app, "depends", depends)
+    if forward_x11 is not None:
+        ec.set(app, "forwardX11", forward_x11)
+    if env is not None:
+        ec.set(app, "env", env)
+    ec.set(app, "command", command)
+
+    ec.register_connection(app, node)
+
+    return app
+
+exp_id = "ping_filters_exp"
+
+# Create the entity Experiment Controller:
+ec = ExperimentController(exp_id)
+
+# Register the nodes resources:
+
+# The username in this case is the slice name, the one to use for login in 
+# via ssh into PlanetLab nodes. Replace with your own slice name.
+username = "inria_sfatest"
+
+# The pluser and plpassword are the ones used to login in the PlanetLab web 
+# site. Replace with your own user and password account information.
+pl_user = "lucia.guevgeozian_odizzio@inria.fr"
+pl_password =  os.environ.get("PL_PASS")
+
+# Choose the PlanetLab nodes for the experiment, in this example 5 nodes are
+# used, and they are picked according to different criterias.
+
+# First node will be the one defined by its hostname.
+hostname = "planetlab2.utt.fr"
+node1 = create_node(ec, username, pl_user, pl_password, hostname=hostname)
+
+# Second node will be any node in France.
+country = "France"
+node2 = create_node(ec, username, pl_user, pl_password, country=country)
+
+# Third node will be a node in France that has Fedora 14 installed.
+operatingSystem = "f14"
+node3 = create_node(ec, username, pl_user, pl_password, country=country,
+                operatingSystem=operatingSystem)
+
+# Forth node will have at least 50% of CPU available
+minCpu=50
+node4 = create_node(ec, username, pl_user, pl_password, minCpu=minCpu)
+
+# Fifth node can be any node, constrains are not important.
+node5 = create_node(ec, username, pl_user, pl_password)
+
+# Register the applications to run in the nodes, in this case just ping to the 
+# first node:
+apps_per_node = dict()
+apps = []
+for node in [node2, node3, node4, node5]:
+    command = "ping -c5 %s > ping%s.txt" % (hostname, node)
+    app = add_app(ec, command, node)
+    apps_per_node[node] = app
+    apps.append(app)
+
+# Register conditions
+
+# The nodes that are completely identified by their hostnames have to be provisioned 
+# before the rest of the nodes. This assures that no other resource will use the
+# identified node even if the constraints matchs. 
+# In this example node2, node3, node4 and node5, are deployed after node1 is 
+# provisioned. node1 must be the node planetlab2.utt.fr, meanwhile node2, node3,
+# node4 and node5 just need to fulfill certain constraints.
+# Applications are always deployed after nodes, so no need to register conditions
+# for the apps in this example.
+
+ec.register_condition(node2, ResourceAction.DEPLOY, node1, ResourceState.PROVISIONED)
+ec.register_condition(node3, ResourceAction.DEPLOY, node1, ResourceState.PROVISIONED)
+ec.register_condition(node4, ResourceAction.DEPLOY, node1, ResourceState.PROVISIONED)
+ec.register_condition(node5, ResourceAction.DEPLOY, node1, ResourceState.PROVISIONED)
+    
+# Deploy the experiment:
+ec.deploy()
+
+# Wait until the applications are finish to retrive the traces:
+ec.wait_finished(apps)
+
+traces = dict() 
+for node, app in apps_per_node.iteritems():
+    ping_string = "ping%s.txt" % node
+    trace = ec.trace(app, ping_string)
+    traces[node]= trace
+
+# Choose a directory to store the traces locally, change to a convenient path for you:
+directory = "examples/planetlab/"
+for node, trace in traces.iteritems():
+    trace_file = directory + "ping%s.txt" % node
+    f = open(trace_file, "w")
+    f.write(trace)
+    f.close()
+
+# Do the experiment controller shutdown:
+ec.shutdown()
+
+# END
diff --git a/examples/planetlab/ping_sfa.py b/examples/planetlab/ping_sfa.py
new file mode 100755 (executable)
index 0000000..c5b393e
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
+
+from nepi.execution.ec import ExperimentController
+import os
+
+# Create the EC
+exp_id = "sfa_test"
+ec = ExperimentController(exp_id)
+
+username = os.environ.get('SFA_SLICE')
+sfauser = os.environ.get('SFA_USER')
+sfaPrivateKey = os.environ.get('SFA_PK')
+
+# server
+node1 = ec.register_resource("PlanetlabSfaNode")
+ec.set(node1, "hostname", 'planetlab-4.imperial.ac.uk')
+ec.set(node1, "username", username)
+ec.set(node1, "sfauser", sfauser)
+ec.set(node1, "sfaPrivateKey", sfaPrivateKey)
+ec.set(node1, "cleanHome", True)
+ec.set(node1, "cleanProcesses", True)
+
+app1 = ec.register_resource("LinuxApplication")
+command = "ping -c5 google.com" 
+ec.set(app1, "command", command)
+ec.register_connection(app1, node1)
+
+# Deploy
+ec.deploy()
+
+ec.wait_finished([app1])
+
+ec.shutdown()
+
+# End
index aa9bfc6..01ac52a 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -20,8 +20,10 @@ setup(
             "nepi.resources.all",
             "nepi.resources.linux",
             "nepi.resources.linux.ccn",
+            "nepi.resources.linux.ns3",
             "nepi.resources.netns",
             "nepi.resources.ns3",
+            "nepi.resources.ns3.classes",
             "nepi.resources.omf",
             "nepi.resources.planetlab",
             "nepi.resources.planetlab.openvswitch",
@@ -29,6 +31,7 @@ setup(
         package_dir = {"": "src"},
         package_data = {
             "nepi.resources.planetlab" : [ "scripts/*.py" ],
-            "nepi.resources.linux" : [ "scripts/*.py" ]
+            "nepi.resources.linux" : [ "scripts/*.py" ],
+            "nepi.resources.linux.ns3" : [ "dependencies/*.tar.gz" ]
             }
     )
index e9f4c54..fa2b104 100644 (file)
@@ -30,16 +30,30 @@ class Flags:
     """ Differents flags to characterize an attribute
 
     """
-    # Attribute can be modified by the user 
-    NoFlags         = 0x00
-    # Attribute is not modifiable by the user
-    ReadOnly        = 0x01
-    # Attribute is not modifiable by the user during runtime
-    ExecReadOnly        = 0x02
-    # Attribute is an access credential
-    Credential      = 0x04
+    # Attribute value can not be read (it is hidden to the user) 
+    NoRead    = 1 # 1
+    
+    # Attribute value can not be modified (it is not editable by the user)
+    NoWrite   = 1 << 1 # 2
+    
+    # Attribute value can be modified only before deployment
+    Design  = 1 << 2 # 4
+
+    # Attribute value will be used at deployment time for initial configuration
+    Construct    = 1 << 3 #  8
+
+    # Attribute provides credentials to access resources
+    Credential  = 1 << 4  | Design # 16 + 4
+
     # Attribute is a filter used to discover resources
-    Filter      = 0x08
+    Filter  = 1 << 5 | Design # 32 + 4
+
+    # Attribute Flag is reserved for internal RM usage (i.e. should be 
+    # transparent to the user)
+    Reserved  = 1 << 6 # 64
+
+    # Attribute global is set to all resources of rtype
+    Global  = 1 << 7 # 128
 
 class Attribute(object):
     """
@@ -77,18 +91,18 @@ class Attribute(object):
                 attributes.
         :type range: (int, int) or (float, float)
         
-        :param set_hook: Function that will be executed when ever a new 
+        :param set_hook: Function that will be executed whenever a new 
                 value is set for the attribute.
         :type set_hook: function
 
     """
     def __init__(self, name, help, type = Types.String,
-            flags = Flags.NoFlags, default = None, allowed = None,
+            flags = None, default = None, allowed = None,
             range = None, set_hook = None):
         self._name = name
         self._help = help
         self._type = type
-        self._flags = flags
+        self._flags = flags or 0
         self._allowed = allowed
         self._range = range
         self._default = self._value = default
@@ -134,7 +148,7 @@ class Attribute(object):
     def has_flag(self, flag):
         """ Returns true if the attribute has the flag 'flag'
 
-        :param flag: Flag that need to be ckecked
+        :param flag: Flag to be checked
         :type flag: Flags
         """
         return (self._flags & flag) == flag
@@ -152,6 +166,9 @@ class Attribute(object):
 
         if self.type in [Types.Double, Types.Integer] and self.range:
             (min, max) = self.range
+
+            value = float(value)
+
             valid = (value >= min and value <= max) 
         
         valid = valid and self.is_valid_value(value)
@@ -173,3 +190,6 @@ class Attribute(object):
         adequate validation"""
         return True
 
+    def has_changed(self):
+        """ Returns true if the value has changed from the default """
+        return self.value != self.default
index 47110a4..5584c68 100644 (file)
@@ -31,7 +31,6 @@ from nepi.execution.trace import TraceAttr
 import functools
 import logging
 import os
-import random
 import sys
 import time
 import threading
@@ -65,20 +64,25 @@ class FailureManager(object):
     def abort(self):
         if self._failure_level == FailureLevel.OK:
             for guid in self.ec.resources:
-                state = self.ec.state(guid)
-                critical = self.ec.get(guid, "critical")
-                if state == ResourceState.FAILED and critical:
-                    self._failure_level = FailureLevel.RM_FAILURE
-                    self.ec.logger.debug("RM critical failure occurred on guid %d." \
-                            " Setting EC FAILURE LEVEL to RM_FAILURE" % guid)
-                    break
+                try:
+                    state = self.ec.state(guid)
+                    critical = self.ec.get(guid, "critical")
+                    if state == ResourceState.FAILED and critical:
+                        self._failure_level = FailureLevel.RM_FAILURE
+                        self.ec.logger.debug("RM critical failure occurred on guid %d." \
+                                " Setting EC FAILURE LEVEL to RM_FAILURE" % guid)
+                        break
+                except:
+                    # An error might occure because a RM was deleted abruptly.
+                    # In this case the error should be ignored.
+                    if guid in self.ec._resources:
+                        raise
 
         return self._failure_level != FailureLevel.OK
 
     def set_ec_failure(self):
         self._failure_level = FailureLevel.EC_FAILURE
 
-
 class ECState(object):
     """ Possible states for an ExperimentController
    
@@ -197,6 +201,16 @@ class ExperimentController(object):
         # EC state
         self._state = ECState.RUNNING
 
+        # Blacklist file for PL nodes
+        nepi_home = os.path.join(os.path.expanduser("~"), ".nepi")
+        plblacklist_file = os.path.join(nepi_home, "plblacklist.txt")
+        if not os.path.exists(plblacklist_file):
+            if os.path.isdir(nepi_home):
+                open(plblacklist_file, 'w').close()
+            else:
+                os.makedirs(nepi_home)
+                open(plblacklist_file, 'w').close()
+                    
         # The runner is a pool of threads used to parallelize 
         # execution of tasks
         nthreads = int(os.environ.get("NEPI_NTHREADS", "50"))
@@ -207,7 +221,7 @@ class ExperimentController(object):
         self._thread = threading.Thread(target = self._process)
         self._thread.setDaemon(True)
         self._thread.start()
-
+        
     @property
     def logger(self):
         """ Returns the logger instance of the Experiment Controller
@@ -369,7 +383,11 @@ class ExperimentController(object):
             :rtype: ResourceManager
             
         """
-        return self._resources.get(guid)
+        rm = self._resources.get(guid)
+        return rm
+
+    def remove_resource(self, guid):
+        del self._resources[guid]
 
     @property
     def resources(self):
@@ -379,7 +397,9 @@ class ExperimentController(object):
             :rtype: set
 
         """
-        return self._resources.keys()
+        keys = self._resources.keys()
+
+        return keys
 
     def register_resource(self, rtype, guid = None):
         """ Registers a new ResourceManager of type 'rtype' in the experiment
@@ -608,7 +628,39 @@ class ExperimentController(object):
 
         """
         rm = self.get_resource(guid)
-        return rm.set(name, value)
+        rm.set(name, value)
+
+    def get_global(self, rtype, name):
+        """ Returns the value of the global attribute with name 'name' on the
+        RMs of rtype 'rtype'.
+
+            :param guid: Guid of the RM
+            :type guid: int
+
+            :param name: Name of the attribute 
+            :type name: str
+
+            :return: The value of the attribute with name 'name'
+
+        """
+        rclass = ResourceFactory.get_resource_type(rtype)
+        return rclass.get_global(name)
+
+    def set_global(self, rtype, name, value):
+        """ Modifies the value of the global attribute with name 'name' on the 
+        RMs of with rtype 'rtype'.
+
+            :param guid: Guid of the RM
+            :type guid: int
+
+            :param name: Name of the attribute
+            :type name: str
+
+            :param value: Value of the attribute
+
+        """
+        rclass = ResourceFactory.get_resource_type(rtype)
+        return rclass.set_global(name, value)
 
     def state(self, guid, hr = False):
         """ Returns the state of a resource
@@ -655,6 +707,41 @@ class ExperimentController(object):
         rm = self.get_resource(guid)
         return rm.start()
 
+    def get_start_time(self, guid):
+        """ Returns the start time of the RM as a timestamp """
+        rm = self.get_resource(guid)
+        return rm.start_time
+
+    def get_stop_time(self, guid):
+        """ Returns the stop time of the RM as a timestamp """
+        rm = self.get_resource(guid)
+        return rm.stop_time
+
+    def get_discover_time(self, guid):
+        """ Returns the discover time of the RM as a timestamp """
+        rm = self.get_resource(guid)
+        return rm.discover_time
+
+    def get_provision_time(self, guid):
+        """ Returns the provision time of the RM as a timestamp """
+        rm = self.get_resource(guid)
+        return rm.provision_time
+
+    def get_ready_time(self, guid):
+        """ Returns the deployment time of the RM as a timestamp """
+        rm = self.get_resource(guid)
+        return rm.ready_time
+
+    def get_release_time(self, guid):
+        """ Returns the release time of the RM as a timestamp """
+        rm = self.get_resource(guid)
+        return rm.release_time
+
+    def get_failed_time(self, guid):
+        """ Returns the time failure occured for the RM as a timestamp """
+        rm = self.get_resource(guid)
+        return rm.failed_time
+
     def set_with_conditions(self, name, value, guids1, guids2, state,
             time = None):
         """ Modifies the value of attribute with name 'name' on all RMs 
@@ -747,7 +834,6 @@ class ExperimentController(object):
                     break
 
             if reschedule:
-
                 callback = functools.partial(wait_all_and_start, group)
                 self.schedule("1s", callback)
             else:
@@ -756,6 +842,11 @@ class ExperimentController(object):
                     rm = self.get_resource(guid)
                     self.schedule("0s", rm.start_with_conditions)
 
+                    if rm.conditions.get(ResourceAction.STOP):
+                        # Only if the RM has STOP conditions we
+                        # schedule a stop. Otherwise the RM will stop immediately
+                        self.schedule("0s", rm.stop_with_conditions)
+
         if wait_all_ready and new_group:
             # Schedule a function to check that all resources are
             # READY, and only then schedule the start.
@@ -774,10 +865,10 @@ class ExperimentController(object):
             if not wait_all_ready:
                 self.schedule("0s", rm.start_with_conditions)
 
-            if rm.conditions.get(ResourceAction.STOP):
-                # Only if the RM has STOP conditions we
-                # schedule a stop. Otherwise the RM will stop immediately
-                self.schedule("0s", rm.stop_with_conditions)
+                if rm.conditions.get(ResourceAction.STOP):
+                    # Only if the RM has STOP conditions we
+                    # schedule a stop. Otherwise the RM will stop immediately
+                    self.schedule("0s", rm.stop_with_conditions)
 
     def release(self, guids = None):
         """ Releases all ResourceManagers in the guids list.
@@ -789,20 +880,21 @@ class ExperimentController(object):
             :type guids: list
 
         """
+        if isinstance(guids, int):
+            guids = [guids]
+
         if not guids:
             guids = self.resources
 
-        # Remove all pending tasks from the scheduler queue
-        for tid in list(self._scheduler.pending):
-            self._scheduler.remove(tid)
-
-        self._runner.empty()
-
         for guid in guids:
             rm = self.get_resource(guid)
             self.schedule("0s", rm.release)
 
         self.wait_released(guids)
+
+        for guid in guids:
+            if self.get(guid, "hardRelease"):
+                self.remove_resource(guid)
         
     def shutdown(self):
         """ Releases all resources and stops the ExperimentController
@@ -812,6 +904,13 @@ class ExperimentController(object):
         if self._state == ECState.FAILED:
             raise RuntimeError("EC failure. Can not exit gracefully")
 
+        # Remove all pending tasks from the scheduler queue
+        for tid in list(self._scheduler.pending):
+            self._scheduler.remove(tid)
+
+        # Remove pending tasks from the workers queue
+        self._runner.empty()
+
         self.release()
 
         # Mark the EC state as TERMINATED
@@ -953,11 +1052,10 @@ class ExperimentController(object):
             :type task: Task
 
         """
-        # Invoke callback
-        task.status = TaskStatus.DONE
-
         try:
+            # Invoke callback
             task.result = task.callback()
+            task.status = TaskStatus.DONE
         except:
             import traceback
             err = traceback.format_exc()
index 49b842b..ba84805 100644 (file)
@@ -186,16 +186,24 @@ class ResourceManager(Logger):
         attributes.
 
         """
-        
         critical = Attribute("critical", 
                 "Defines whether the resource is critical. "
                 "A failure on a critical resource will interrupt "
                 "the experiment. ",
                 type = Types.Bool,
                 default = True,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
+        hard_release = Attribute("hardRelease", 
+                "Forces removal of all result files and directories associated "
+                "to the RM upon resource release. After release the RM will "
+                "be removed from the EC and the results will not longer be "
+                "accessible",
+                type = Types.Bool,
+                default = False,
+                flags = Flags.Design)
 
         cls._register_attribute(critical)
+        cls._register_attribute(hard_release)
         
     @classmethod
     def _register_traces(cls):
@@ -289,6 +297,32 @@ class ResourceManager(Logger):
         """
         return cls._backend
 
+    @classmethod
+    def get_global(cls, name):
+        """ Returns the value of a global attribute
+            Global attribute meaning an attribute for 
+            all the resources from a rtype
+
+        :param name: Name of the attribute
+        :type name: str
+        :rtype: str
+        """
+        global_attr = cls._attributes[name]
+        return global_attr.value
+
+    @classmethod
+    def set_global(cls, name, value):
+        """ Set value for a global attribute
+
+        :param name: Name of the attribute
+        :type name: str
+        :param name: Value of the attribute
+        :type name: str
+        """
+        global_attr = cls._attributes[name]
+        global_attr.value = value
+        return value
+
     def __init__(self, ec, guid):
         super(ResourceManager, self).__init__(self.get_rtype())
         
@@ -512,7 +546,6 @@ class ResourceManager(Logger):
         with self._release_lock:
             if self._state != ResourceState.RELEASED:
                 self.do_deploy()
-                self.debug("----- READY ---- ")
 
     def release(self):
         """ Perform actions to free resources used by the RM.
@@ -531,8 +564,8 @@ class ResourceManager(Logger):
                 import traceback
                 err = traceback.format_exc()
                 self.error(err)
+
                 self.set_released()
-                self.debug("----- RELEASED ---- ")
 
     def fail(self):
         """ Sets the RM to state FAILED.
@@ -555,6 +588,7 @@ class ResourceManager(Logger):
         """
         attr = self._attrs[name]
         attr.value = value
+        return value
 
     def get(self, name):
         """ Returns the value of the attribute
@@ -564,8 +598,39 @@ class ResourceManager(Logger):
         :rtype: str
         """
         attr = self._attrs[name]
+        if attr.has_flag(Flags.Global):
+            self.warning( "Attribute %s is global. Use get_global instead." % name)
+            
         return attr.value
 
+    def has_changed(self, name):
+        """ Returns the True is the value of the attribute
+            has been modified by the user.
+
+        :param name: Name of the attribute
+        :type name: str
+        :rtype: str
+        """
+        attr = self._attrs[name]
+        return attr.has_changed()
+
+    def has_flag(self, name, flag):
+        """ Returns true if the attribute has the flag 'flag'
+
+        :param flag: Flag to be checked
+        :type flag: Flags
+        """
+        attr = self._attrs[name]
+        return attr.has_flag(flag)
+
+    def has_attribute(self, name):
+        """ Returns true if the RM has an attribute with name
+
+        :param name: name of the attribute
+        :type name: string
+        """
+        return name in self._attrs
+
     def enable_trace(self, name):
         """ Explicitly enable trace generation
 
@@ -676,6 +741,7 @@ class ResourceManager(Logger):
         connected = []
         rclass = ResourceFactory.get_resource_type(rtype)
         for guid in self.connections:
+
             rm = self.ec.get_resource(guid)
             if not rtype or isinstance(rm, rclass):
                 connected.append(rm)
@@ -946,7 +1012,6 @@ class ResourceManager(Logger):
 
     def do_release(self):
         self.set_released()
-        self.debug("----- RELEASED ---- ")
 
     def do_fail(self):
         self.set_failed()
@@ -954,30 +1019,37 @@ class ResourceManager(Logger):
     def set_started(self):
         """ Mark ResourceManager as STARTED """
         self.set_state(ResourceState.STARTED, "_start_time")
-        
+        self.debug("----- STARTED ---- ")
+
     def set_stopped(self):
         """ Mark ResourceManager as STOPPED """
         self.set_state(ResourceState.STOPPED, "_stop_time")
+        self.debug("----- STOPPED ---- ")
 
     def set_ready(self):
         """ Mark ResourceManager as READY """
         self.set_state(ResourceState.READY, "_ready_time")
+        self.debug("----- READY ---- ")
 
     def set_released(self):
         """ Mark ResourceManager as REALEASED """
         self.set_state(ResourceState.RELEASED, "_release_time")
+        self.debug("----- RELEASED ---- ")
 
     def set_failed(self):
         """ Mark ResourceManager as FAILED """
         self.set_state(ResourceState.FAILED, "_failed_time")
+        self.debug("----- FAILED ---- ")
 
     def set_discovered(self):
         """ Mark ResourceManager as DISCOVERED """
         self.set_state(ResourceState.DISCOVERED, "_discover_time")
+        self.debug("----- DISCOVERED ---- ")
 
     def set_provisioned(self):
         """ Mark ResourceManager as PROVISIONED """
         self.set_state(ResourceState.PROVISIONED, "_provision_time")
+        self.debug("----- PROVISIONED ---- ")
 
     def set_state(self, state, state_time_attr):
         """ Set the state of the RM while keeping a trace of the time """
@@ -1033,7 +1105,7 @@ def find_types():
     path = os.path.dirname(nepi.resources.__file__)
     search_path.add(path)
 
-    types = []
+    types = set()
 
     for importer, modname, ispkg in pkgutil.walk_packages(search_path, 
             prefix = "nepi.resources."):
@@ -1041,7 +1113,7 @@ def find_types():
         loader = importer.find_module(modname)
         
         try:
-            # Notice: Repeated calls to load_module will act as a reload of teh module
+            # Notice: Repeated calls to load_module will act as a reload of the module
             if modname in sys.modules:
                 module = sys.modules.get(modname)
             else:
@@ -1060,7 +1132,7 @@ def find_types():
                     continue
 
                 if issubclass(attr, ResourceManager):
-                    types.append(attr)
+                    types.add(attr)
 
                     if not modname in sys.modules:
                         sys.modules[modname] = module
@@ -1074,4 +1146,3 @@ def find_types():
 
     return types
 
-
index 0b6ad23..f13a392 100644 (file)
@@ -48,14 +48,14 @@ class Collector(ResourceManager):
     @classmethod
     def _register_attributes(cls):
         trace_name = Attribute("traceName", "Name of the trace to be collected", 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         store_dir = Attribute("storeDir", "Path to local directory to store trace results", 
                 default = tempfile.gettempdir(),
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         sub_dir = Attribute("subDir", "Sub directory to collect traces into", 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         rename = Attribute("rename", "Name to give to the collected trace file", 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         cls._register_attribute(trace_name)
         cls._register_attribute(store_dir)
index 0057ad1..45efd21 100644 (file)
@@ -63,14 +63,14 @@ class LinuxApplication(ResourceManager):
         The directory structure used by LinuxApplication RM at the Linux
         host is the following:
 
-        ${HOME}/nepi-usr --> Base directory for multi-experiment files
+        ${HOME}/.nepi/nepi-usr --> Base directory for multi-experiment files
                       |
         ${LIB}        |- /lib --> Base directory for libraries
         ${BIN}        |- /bin --> Base directory for binary files
         ${SRC}        |- /src --> Base directory for sources
         ${SHARE}      |- /share --> Base directory for other files
 
-        ${HOME}/nepi-exp --> Base directory for single-experiment files
+        ${HOME}/.nepi/nepi-exp --> Base directory for single-experiment files
                       |
         ${EXP_HOME}   |- /<exp-id>  --> Base directory for experiment exp-id
                           |
@@ -90,43 +90,43 @@ class LinuxApplication(ResourceManager):
         command = Attribute("command", "Command to execute at application start. "
                 "Note that commands will be executed in the ${RUN_HOME} directory, "
                 "make sure to take this into account when using relative paths. ", 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         forward_x11 = Attribute("forwardX11", "Enables X11 forwarding for SSH connections", 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         env = Attribute("env", "Environment variables string for command execution",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         sudo = Attribute("sudo", "Run with root privileges", 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         depends = Attribute("depends", 
                 "Space-separated list of packages required to run the application",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         sources = Attribute("sources", 
-                "Space-separated list of regular files to be uploaded to ${SRC} "
+                "semi-colon separated list of regular files to be uploaded to ${SRC} "
                 "directory prior to building. Archives won't be expanded automatically. "
                 "Sources are globally available for all experiments unless "
                 "cleanHome is set to True (This will delete all sources). ",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         files = Attribute("files", 
-                "Space-separated list of regular miscellaneous files to be uploaded "
+                "semi-colon separated list of regular miscellaneous files to be uploaded "
                 "to ${SHARE} directory. "
                 "Files are globally available for all experiments unless "
                 "cleanHome is set to True (This will delete all files). ",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         libs = Attribute("libs", 
-                "Space-separated list of libraries (e.g. .so files) to be uploaded "
+                "semi-colon separated list of libraries (e.g. .so files) to be uploaded "
                 "to ${LIB} directory. "
                 "Libraries are globally available for all experiments unless "
                 "cleanHome is set to True (This will delete all files). ",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         bins = Attribute("bins", 
-                "Space-separated list of binary files to be uploaded "
+                "semi-colon separated list of binary files to be uploaded "
                 "to ${BIN} directory. "
                 "Binaries are globally available for all experiments unless "
                 "cleanHome is set to True (This will delete all files). ",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         code = Attribute("code", 
                 "Plain text source code to be uploaded to the ${APP_HOME} directory. ",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         build = Attribute("build", 
                 "Build commands to execute after deploying the sources. "
                 "Sources are uploaded to the ${SRC} directory and code "
@@ -135,16 +135,16 @@ class LinuxApplication(ResourceManager):
                 "./configure && make && make clean.\n"
                 "Make sure to make the build commands return with a nonzero exit "
                 "code on error.",
-                flags = Flags.ReadOnly)
+                flags = Flags.Design)
         install = Attribute("install", 
                 "Commands to transfer built files to their final destinations. "
                 "Install commands are executed after build commands. ",
-                flags = Flags.ReadOnly)
+                flags = Flags.Design)
         stdin = Attribute("stdin", "Standard input for the 'command'", 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         tear_down = Attribute("tearDown", "Command to be executed just before " 
                 "releasing the resource", 
-                flags = Flags.ReadOnly)
+                flags = Flags.Design)
 
         cls._register_attribute(command)
         cls._register_attribute(forward_x11)
@@ -227,10 +227,13 @@ class LinuxApplication(ResourceManager):
         """
         return self.get("forwardX11") or self._in_foreground
 
+    def trace_filepath(self, filename):
+        return os.path.join(self.run_home, filename)
+
     def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0):
         self.info("Retrieving '%s' trace %s " % (name, attr))
 
-        path = os.path.join(self.run_home, name)
+        path = self.trace_filepath(name)
         
         command = "(test -f %s && echo 'success') || echo 'error'" % path
         (out, err), proc = self.node.execute(command)
@@ -272,7 +275,8 @@ class LinuxApplication(ResourceManager):
 
     def do_provision(self):
         # take a snapshot of the system if user is root
-        # to assure cleanProcess kill every nepi process
+        # to ensure that cleanProcess will not kill
+        # pre-existent processes
         if self.node.get("username") == 'root':
             import pickle
             procs = dict()
@@ -353,29 +357,33 @@ class LinuxApplication(ResourceManager):
                     env = env,
                     overwrite = overwrite)
 
-    def execute_deploy_command(self, command):
+    def execute_deploy_command(self, command, prefix="deploy"):
         if command:
             # Upload the command to a bash script and run it
             # in background ( but wait until the command has
             # finished to continue )
-            shfile = os.path.join(self.app_home, "deploy.sh")
+            shfile = os.path.join(self.app_home, "%s.sh" % prefix)
             self.node.run_and_wait(command, self.run_home,
                     shfile = shfile, 
                     overwrite = False,
-                    pidfile = "deploy_pidfile", 
-                    ecodefile = "deploy_exitcode", 
-                    stdout = "deploy_stdout", 
-                    stderr = "deploy_stderr")
-
-    def upload_sources(self):
-        sources = self.get("sources")
+                    pidfile = "%s_pidfile" % prefix, 
+                    ecodefile = "%s_exitcode" % prefix, 
+                    stdout = "%s_stdout" % prefix, 
+                    stderr = "%s_stderr" % prefix)
+
+    def upload_sources(self, sources = None, src_dir = None):
+        if not sources:
+            sources = self.get("sources")
    
         command = ""
 
+        if not src_dir:
+            src_dir = self.node.src_dir
+
         if sources:
             self.info("Uploading sources ")
 
-            sources = sources.split(' ')
+            sources = map(str.strip, sources.split(";"))
 
             # Separate sources that should be downloaded from 
             # the web, from sources that should be uploaded from
@@ -388,15 +396,16 @@ class LinuxApplication(ResourceManager):
 
                     command.append( " ( " 
                             # Check if the source already exists
-                            " ls ${SRC}/%(basename)s "
+                            " ls %(src_dir)s/%(basename)s "
                             " || ( "
                             # If source doesn't exist, download it and check
                             # that it it downloaded ok
-                            "   wget -c --directory-prefix=${SRC} %(source)s && "
-                            "   ls ${SRC}/%(basename)s "
+                            "   wget -c --directory-prefix=%(src_dir)s %(source)s && "
+                            "   ls %(src_dir)s/%(basename)s "
                             " ) ) " % {
                                 "basename": os.path.basename(source),
-                                "source": source
+                                "source": source,
+                                "src_dir": src_dir
                                 })
 
             command = " && ".join(command)
@@ -405,34 +414,38 @@ class LinuxApplication(ResourceManager):
             command = self.replace_paths(command)
        
             if sources:
-                sources = ' '.join(sources)
-                self.node.upload(sources, self.node.src_dir, overwrite = False)
+                sources = ';'.join(sources)
+                self.node.upload(sources, src_dir, overwrite = False)
 
         return command
 
-    def upload_files(self):
-        files = self.get("files")
+    def upload_files(self, files = None):
+        if not files:
+            files = self.get("files")
 
         if files:
             self.info("Uploading files %s " % files)
             self.node.upload(files, self.node.share_dir, overwrite = False)
 
-    def upload_libraries(self):
-        libs = self.get("libs")
+    def upload_libraries(self, libs = None):
+        if not libs:
+            libs = self.get("libs")
 
         if libs:
             self.info("Uploading libraries %s " % libaries)
             self.node.upload(libs, self.node.lib_dir, overwrite = False)
 
-    def upload_binaries(self):
-        bins = self.get("bins")
+    def upload_binaries(self, bins = None):
+        if not bins:
+            bins = self.get("bins")
 
         if bins:
             self.info("Uploading binaries %s " % binaries)
             self.node.upload(bins, self.node.bin_dir, overwrite = False)
 
-    def upload_code(self):
-        code = self.get("code")
+    def upload_code(self, code = None):
+        if not code:
+            code = self.get("code")
 
         if code:
             self.info("Uploading code")
@@ -440,15 +453,21 @@ class LinuxApplication(ResourceManager):
             dst = os.path.join(self.app_home, "code")
             self.node.upload(code, dst, overwrite = False, text = True)
 
-    def upload_stdin(self):
-        stdin = self.get("stdin")
+    def upload_stdin(self, stdin = None):
+        if not stdin:
+           stdin = self.get("stdin")
+
         if stdin:
             # create dir for sources
             self.info("Uploading stdin")
             
             # upload stdin file to ${SHARE_DIR} directory
-            basename = os.path.basename(stdin)
-            dst = os.path.join(self.node.share_dir, basename)
+            if os.path.isfile(stdin):
+                basename = os.path.basename(stdin)
+                dst = os.path.join(self.node.share_dir, basename)
+            else:
+                dst = os.path.join(self.app_home, "stdin")
+
             self.node.upload(stdin, dst, overwrite = False, text = True)
 
             # create "stdin" symlink on ${APP_HOME} directory
@@ -458,14 +477,17 @@ class LinuxApplication(ResourceManager):
 
             return command
 
-    def install_dependencies(self):
-        depends = self.get("depends")
+    def install_dependencies(self, depends = None):
+        if not depends:
+            depends = self.get("depends")
+
         if depends:
             self.info("Installing dependencies %s" % depends)
             return self.node.install_packages_command(depends)
 
-    def build(self):
-        build = self.get("build")
+    def build(self, build = None):
+        if not build:
+            build = self.get("build")
 
         if build:
             self.info("Building sources ")
@@ -473,8 +495,9 @@ class LinuxApplication(ResourceManager):
             # replace application specific paths in the command
             return self.replace_paths(build)
 
-    def install(self):
-        install = self.get("install")
+    def install(self, install = None):
+        if not install:
+            install = self.get("install")
 
         if install:
             self.info("Installing sources ")
@@ -519,10 +542,6 @@ class LinuxApplication(ResourceManager):
         x11 = self.get("forwardX11")
         env = self.get("env")
 
-        # For a command being executed in foreground, if there is stdin,
-        # it is expected to be text string not a file or pipe
-        stdin = self.get("stdin") or None
-
         # Command will be launched in foreground and attached to the
         # terminal using the node 'execute' in non blocking mode.
 
@@ -533,7 +552,6 @@ class LinuxApplication(ResourceManager):
         (out, err), self._proc = self.execute_command(command, 
                 env = env,
                 sudo = sudo,
-                stdin = stdin,
                 forward_x11 = x11,
                 blocking = False)
 
@@ -610,7 +628,7 @@ class LinuxApplication(ResourceManager):
                             sudo = self._sudo_kill)
 
                     # TODO: check if execution errors occurred
-                    if proc.poll() or err:
+                    if (proc and proc.poll()) or err:
                         msg = " Failed to STOP command '%s' " % self.get("command")
                         self.error(msg, out, err)
         
@@ -619,11 +637,15 @@ class LinuxApplication(ResourceManager):
     def do_release(self):
         self.info("Releasing resource")
 
+        self.do_stop()
+        
         tear_down = self.get("tearDown")
         if tear_down:
             self.node.execute(tear_down)
 
-        self.do_stop()
+        hard_release = self.get("hardRelease")
+        if hard_release:
+            self.node.rmdir(self.app_home)
 
         super(LinuxApplication, self).do_release()
         
@@ -681,7 +703,6 @@ class LinuxApplication(ResourceManager):
     def execute_command(self, command, 
             env = None,
             sudo = False,
-            stdin = None,
             forward_x11 = False,
             blocking = False):
 
@@ -693,7 +714,6 @@ class LinuxApplication(ResourceManager):
 
         return self.node.execute(command,
                 sudo = sudo,
-                stdin = stdin,
                 forward_x11 = forward_x11,
                 blocking = blocking)
 
index 89c949c..f79c7cf 100644 (file)
@@ -59,7 +59,6 @@ class LinuxCCNApplication(LinuxApplication):
             self.do_discover()
             self.do_provision()
 
-            self.debug("----- READY ---- ")
             self.set_ready()
 
     @property
index 84f6185..c7ce3bf 100644 (file)
@@ -34,11 +34,11 @@ class LinuxCCNContent(LinuxApplication):
     def _register_attributes(cls):
         content_name = Attribute("contentName",
                 "The name of the content to publish (e.g. ccn:/VIDEO) ",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         content = Attribute("content",
                 "The content to publish. It can be a path to a file or plain text ",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         scope = Attribute("scope",
                 "Use the given scope on the start-write request (if -r specified). "
@@ -46,7 +46,7 @@ class LinuxCCNContent(LinuxApplication):
                 "Note that a scope of 3 is encoded as the absence of any scope in the interest. ",
                 type = Types.Integer,
                 default = 1,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         cls._register_attribute(content_name)
         cls._register_attribute(content)
@@ -96,7 +96,6 @@ class LinuxCCNContent(LinuxApplication):
             self.do_discover()
             self.do_provision()
 
-            self.debug("----- READY ---- ")
             self.set_ready()
 
     def upload_start_command(self):
index e4bc39a..ffaee50 100644 (file)
@@ -50,56 +50,56 @@ class LinuxCCND(LinuxApplication):
             "  -1 - max logging \n"
             "  Or apply bitwise OR to these values to get combinations of them",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         port = Attribute("port", "Sets the CCN_LOCAL_PORT environmental variable. "
             "Defaults to 9695 ", 
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
  
         sockname = Attribute("sockname",
             "Sets the CCN_LOCAL_SCOKNAME environmental variable. "
             "Defaults to /tmp/.ccnd.sock", 
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         capacity = Attribute("capacity",
             "Sets the CCND_CAP environmental variable. "
             "Capacity limit in terms of ContentObjects",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         mtu = Attribute("mtu", "Sets the CCND_MTU environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
   
         data_pause = Attribute("dataPauseMicrosec",
             "Sets the CCND_DATA_PAUSE_MICROSEC environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         default_stale = Attribute("defaultTimeToStale",
              "Sets the CCND_DEFAULT_TIME_TO_STALE environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         max_stale = Attribute("maxTimeToStale",
             "Sets the CCND_MAX_TIME_TO_STALE environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         max_rte = Attribute("maxRteMicrosec",
             "Sets the CCND_MAX_RTE_MICROSEC environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         keystore = Attribute("keyStoreDirectory",
             "Sets the CCND_KEYSTORE_DIRECTORY environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         listen_on = Attribute("listenOn",
             "Sets the CCND_LISTEN_ON environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         autoreg = Attribute("autoreg",
             "Sets the CCND_AUTOREG environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         prefix = Attribute("prefix",
             "Sets the CCND_PREFIX environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(debug)
         cls._register_attribute(port)
@@ -176,7 +176,6 @@ class LinuxCCND(LinuxApplication):
             self.do_discover()
             self.do_provision()
 
-            self.debug("----- READY ---- ")
             self.set_ready()
 
     def upload_start_command(self):
@@ -195,8 +194,7 @@ class LinuxCCND(LinuxApplication):
         self.node.run_and_wait(command, self.run_home,
                 shfile = shfile,
                 overwrite = False,
-                env = env,
-                raise_on_error = True)
+                env = env)
 
     def do_start(self):
         if self.state == ResourceState.READY:
index f654a2a..cbe599e 100644 (file)
@@ -34,21 +34,21 @@ class LinuxCCNPing(LinuxCCNPingServer):
         interval = Attribute("i",
             "Set ping interval in seconds (minimum 0.10 second) ",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         count = Attribute("c",
             "Total number of pings",
             type = Types.Double,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         number = Attribute("n",
             "Set the starting number, the number is incremented by 1 after each Interest ",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
  
         prefix = Attribute("prefix",
             "Prefix to serve content (e.g. ccnx:/name/prefix)",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(interval)
         cls._register_attribute(count)
index 2dee4db..865b104 100644 (file)
@@ -35,16 +35,16 @@ class LinuxCCNPingServer(LinuxCCNApplication):
             "Run ccnping server as a daemon in background",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         freshness = Attribute("x",
             "Set FreshnessSeconds",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         prefix = Attribute("prefix",
             "Prefix to serve content (e.g. ccnx:/name/prefix)",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(daemon)
         cls._register_attribute(freshness)
index e65779a..9ac5cce 100644 (file)
@@ -35,23 +35,23 @@ class LinuxCCNR(LinuxApplication):
     def _register_attributes(cls):
         max_fanout = Attribute("maxFanout",
             "Sets the CCNR_BTREE_MAX_FANOUT environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         max_leaf_entries = Attribute("maxLeafEntries",
             "Sets the CCNR_BTREE_MAX_LEAF_ENTRIES environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         max_node_bytes = Attribute("maxNodeBytes",
             "Sets the CCNR_BTREE_MAX_NODE_BYTES environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         max_node_pool = Attribute("maxNodePool",
             "Sets the CCNR_BTREE_MAX_NODE_POOL environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         content_cache = Attribute("contentCache",
             "Sets the CCNR_CONTENT_CACHE environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         debug = Attribute("debug",
             "Sets the CCNR_DEBUG environmental variable. "
@@ -64,92 +64,92 @@ class LinuxCCNR(LinuxApplication):
                     "WARNING",
                     "INFO",
                     "FINE, FINER, FINEST"],
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         directory = Attribute("directory",
             "Sets the CCNR_DIRECTORY environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         global_prefix = Attribute("globalPrefix",
             "Sets the CCNR_GLOBAL_PREFIX environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         listen_on = Attribute("listenOn",
             "Sets the CCNR_LISTEN_ON environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         min_send_bufsize = Attribute("minSendBufsize",
             "Sets the CCNR_MIN_SEND_BUFSIZE environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         proto = Attribute("proto",
             "Sets the CCNR_PROTO environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         status_port = Attribute("statusPort",
             "Sets the CCNR_STATUS_PORT environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         start_write_scope_limit = Attribute("startWriteScopeLimit",
             "Sets the CCNR_START_WRITE_SCOPE_LIMIT environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_debug = Attribute("ccnsDebug",
             "Sets the CCNS_DEBUG environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_enable = Attribute("ccnsEnable",
             "Sets the CCNS_ENABLE environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_faux_error = Attribute("ccnsFauxError",
             "Sets the CCNS_FAUX_ERROR environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_heartbeat_micros = Attribute("ccnsHeartBeatMicros",
             "Sets the CCNS_HEART_BEAT_MICROS environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_max_compares_busy = Attribute("ccnsMaxComparesBusy",
             "Sets the CCNS_MAX_COMPARES_BUSY environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_max_fetch_busy = Attribute("ccnsMaxFetchBusy",
             "Sets the CCNS_MAX_FETCH_BUSY environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_node_fetch_lifetime = Attribute("ccnsNodeFetchLifetime",
             "Sets the CCNS_NODE_FETCH_LIFETIME environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_note_err = Attribute("ccnsNoteErr",
             "Sets the CCNS_NOTE_ERR environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_repo_store = Attribute("ccnsRepoStore",
             "Sets the CCNS_REPO_STORE environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_root_advise_fresh = Attribute("ccnsRootAdviseFresh",
             "Sets the CCNS_ROOT_ADVISE_FRESH environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_root_advise_lifetime = Attribute("ccnsRootAdviseLifetime",
             "Sets the CCNS_ROOT_ADVISE_LIFETIME environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_stable_enabled = Attribute("ccnsStableEnabled",
             "Sets the CCNS_STABLE_ENABLED environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ccns_sync_scope = Attribute("ccnsSyncScope",
             "Sets the CCNS_SYNC_SCOPE environmental variable. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         repo_file = Attribute("repoFile1",
             "The Repository uses $CCNR_DIRECTORY/repoFile1 for "
             "persistent storage of CCN Content Objects",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(max_fanout)
         cls._register_attribute(max_leaf_entries)
@@ -220,7 +220,6 @@ class LinuxCCNR(LinuxApplication):
             self.do_discover()
             self.do_provision()
 
-            self.debug("----- READY ---- ")
             self.set_ready()
 
     def upload_start_command(self):
@@ -248,8 +247,7 @@ class LinuxCCNR(LinuxApplication):
         self.node.run_and_wait(command, self.run_home,
                 shfile = shfile,
                 overwrite = False,
-                env = env,
-                raise_on_error = True)
+                env = env)
 
     def do_start(self):
         if self.state == ResourceState.READY:
index cebc105..dca91c2 100644 (file)
@@ -42,7 +42,7 @@ class LinuxFIBEntry(LinuxApplication):
         uri = Attribute("uri",
                 "URI prefix to match and route for this FIB entry",
                 default = "ccnx:/",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         protocol = Attribute("protocol",
                 "Transport protocol used in network connection to peer "
@@ -50,20 +50,20 @@ class LinuxFIBEntry(LinuxApplication):
                 type = Types.Enumerate, 
                 default = "udp",
                 allowed = ["udp", "tcp"],
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         host = Attribute("host",
                 "Peer hostname used in network connection for this FIB entry. ",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         port = Attribute("port",
                 "Peer port address used in network connection to peer "
                 "for this FIB entry.",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         ip = Attribute("ip",
                 "Peer host public IP used in network connection for this FIB entry. ",
-                flags = Flags.ReadOnly)
+                flags = Flags.Design)
 
         cls._register_attribute(uri)
         cls._register_attribute(protocol)
@@ -134,7 +134,6 @@ class LinuxFIBEntry(LinuxApplication):
             self.do_provision()
             self.configure()
 
-            self.debug("----- READY ---- ")
             self.set_ready()
 
     def upload_start_command(self):
index 7b8eadc..bb352e1 100644 (file)
@@ -30,8 +30,9 @@ import re
 import tempfile
 import time
 
-# TODO: UP, MTU attributes!
-
+# TODO: 
+#     - check UP, MTU attributes!
+#     - clean up code and test!
 
 @clsinit_copy
 class LinuxInterface(ResourceManager):
@@ -42,33 +43,33 @@ class LinuxInterface(ResourceManager):
     @classmethod
     def _register_attributes(cls):
         ip4 = Attribute("ip4", "IPv4 Address",
-              flags = Flags.ExecReadOnly)
+              flags = Flags.Design)
 
         ip6 = Attribute("ip6", "IPv6 Address",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         mac = Attribute("mac", "MAC Address",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         mask4 = Attribute("mask4", "IPv4 network mask",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         mask6 = Attribute("mask6", "IPv6 network mask",
                 type = Types.Integer,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         mtu = Attribute("mtu", "Maximum transmition unit for device",
                 type = Types.Integer)
 
         devname = Attribute("deviceName", 
                 "Name of the network interface (e.g. eth0, wlan0, etc)",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         up = Attribute("up", "Link up", type = Types.Bool)
 
         tear_down = Attribute("tearDown", "Bash script to be executed before " + \
                 "releasing the resource",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         cls._register_attribute(ip4)
         cls._register_attribute(ip6)
@@ -266,6 +267,7 @@ class LinuxInterface(ResourceManager):
         attr = self._attrs["up"]
         attr._value = up
         attr = self._attrs["mtu"]
+        attr._value = mtu 
 
     def add_set_hooks(self):
         attrup = self._attrs["up"]
@@ -275,7 +277,7 @@ class LinuxInterface(ResourceManager):
         attrmtu.set_hook = self.set_hook_mtu
 
     def set_hook_up(self, oldval, newval):
-        if oldval == newval:
+        if self.state == ResourceState.NEW or oldval == newval:
             return oldval
 
         # configure interface up
@@ -294,7 +296,7 @@ class LinuxInterface(ResourceManager):
         return newval
 
     def set_hook_mtu(self, oldval, newval):
-        if oldval == newval:
+        if self.state == ResourceState.NEW or oldval == newval:
             return oldval
 
         cmd = "ifconfig %s mtu %d" % (self.get("deviceName"), newval)
index 1edc6b5..b694443 100644 (file)
@@ -34,41 +34,41 @@ class LinuxMtr(LinuxApplication):
             "sets mtr --report-cycles (-c) option. Determines the number of "
             "pings sent to determine both machines in the networks. Each "
             "cycle lasts one sencond.",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         no_dns = Attribute("noDns",
             "sets mtr --no-dns (-n) option. Forces mtr to display IPs intead of "
             "trying to resolve to host names ",
             type = Types.Bool,
             default = True,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         address = Attribute("address",
             "sets mtr --address (-a) option. Binds the socket to send outgoing "
             "packets to the interface of the specified address, so that any "
             "any packets are sent through this interface. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         interval = Attribute("interval",
             "sets mtr --interval (-i) option. Specifies the number of seconds "
             "between ICMP ECHO requests. Default value is one second ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         countinuous = Attribute("continuous",
             "Run mtr in a while loop",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         print_timestamp = Attribute("printTimestamp",
             "Print timestamp before running mtr",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         target = Attribute("target",
             "mtr target host (host that will be pinged)",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(report_cycles)
         cls._register_attribute(no_dns)
index f75368d..6de7cd9 100644 (file)
@@ -149,50 +149,50 @@ class LinuxNode(ResourceManager):
     @classmethod
     def _register_attributes(cls):
         hostname = Attribute("hostname", "Hostname of the machine",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         username = Attribute("username", "Local account username", 
                 flags = Flags.Credential)
 
-        port = Attribute("port", "SSH port", flags = Flags.ExecReadOnly)
+        port = Attribute("port", "SSH port", flags = Flags.Design)
         
         home = Attribute("home",
                 "Experiment home directory to store all experiment related files",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         
         identity = Attribute("identity", "SSH identity file",
                 flags = Flags.Credential)
         
         server_key = Attribute("serverKey", "Server public key", 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         
         clean_home = Attribute("cleanHome", "Remove all nepi files and directories "
                 " from node home folder before starting experiment", 
                 type = Types.Bool,
                 default = False,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         clean_experiment = Attribute("cleanExperiment", "Remove all files and directories " 
                 " from a previous same experiment, before the new experiment starts", 
                 type = Types.Bool,
                 default = False,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         
         clean_processes = Attribute("cleanProcesses", 
                 "Kill all running processes before starting experiment",
                 type = Types.Bool,
                 default = False,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         
         tear_down = Attribute("tearDown", "Bash script to be executed before " + \
                 "releasing the resource",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         gateway_user = Attribute("gatewayUser", "Gateway account username",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         gateway = Attribute("gateway", "Hostname of the gateway machine",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         cls._register_attribute(hostname)
         cls._register_attribute(username)
@@ -233,9 +233,13 @@ class LinuxNode(ResourceManager):
            home = os.path.join(self._home_dir, home) 
         return home
 
+    @property
+    def nepi_home(self):
+        return os.path.join(self.home_dir, ".nepi")
+
     @property
     def usr_dir(self):
-        return os.path.join(self.home_dir, "nepi-usr")
+        return os.path.join(self.nepi_home, "nepi-usr")
 
     @property
     def lib_dir(self):
@@ -255,7 +259,7 @@ class LinuxNode(ResourceManager):
 
     @property
     def exp_dir(self):
-        return os.path.join(self.home_dir, "nepi-exp")
+        return os.path.join(self.nepi_home, "nepi-exp")
 
     @property
     def exp_home(self):
@@ -274,7 +278,8 @@ class LinuxNode(ResourceManager):
         if self._os:
             return self._os
 
-        if (not self.get("hostname") or not self.get("username")):
+        if self.get("hostname") not in ["localhost", "127.0.0.1"] and \
+                not self.get("username"):
             msg = "Can't resolve OS, insufficient data "
             self.error(msg)
             raise RuntimeError, msg
@@ -348,14 +353,14 @@ class LinuxNode(ResourceManager):
         if self.get("cleanExperiment"):
             self.clean_experiment()
     
-        # Create shared directory structure
-        self.mkdir(self.lib_dir)
-        self.mkdir(self.bin_dir)
-        self.mkdir(self.src_dir)
-        self.mkdir(self.share_dir)
+        # Create shared directory structure and node home directory
+        paths = [self.lib_dir, 
+            self.bin_dir, 
+            self.src_dir, 
+            self.share_dir, 
+            self.node_home]
 
-        # Create experiment node home directory
-        self.mkdir(self.node_home)
+        self.mkdir(paths)
 
         super(LinuxNode, self).do_provision()
 
@@ -400,9 +405,11 @@ class LinuxNode(ResourceManager):
     def clean_processes(self):
         self.info("Cleaning up processes")
  
+        if self.get("hostname") in ["localhost", "127.0.0.2"]:
+            return 
+        
         if self.get("username") != 'root':
             cmd = ("sudo -S killall tcpdump || /bin/true ; " +
-                "sudo -S kill $(ps aux | grep '[n]epi' | awk '{print $2}') || /bin/true ; " +
                 "sudo -S killall -u %s || /bin/true ; " % self.get("username"))
         else:
             if self.state >= ResourceState.READY:
@@ -424,7 +431,6 @@ class LinuxNode(ResourceManager):
                 cmd = ("killall tcpdump || /bin/true ; " +
                     "kill $(ps aux | grep '[n]epi' | awk '{print $2}') || /bin/true ; ")
 
-        out = err = ""
         (out, err), proc = self.execute(cmd, retry = 1, with_lock = True)
 
     def clean_home(self):
@@ -432,7 +438,7 @@ class LinuxNode(ResourceManager):
         """
         self.info("Cleaning up home")
         
-        cmd = "cd %s ; find . -maxdepth 1 \( -name 'nepi-usr' -o -name 'nepi-exp' \) -execdir rm -rf {} + " % (
+        cmd = "cd %s ; find . -maxdepth 1 -name \.nepi -execdir rm -rf {} + " % (
                 self.home_dir )
 
         return self.execute(cmd, with_lock = True)
@@ -452,13 +458,10 @@ class LinuxNode(ResourceManager):
 
     def execute(self, command,
             sudo = False,
-            stdin = None, 
             env = None,
             tty = False,
             forward_x11 = False,
-            timeout = None,
             retry = 3,
-            err_on_timeout = True,
             connect_timeout = 30,
             strict_host_checking = False,
             persistent = True,
@@ -473,10 +476,13 @@ class LinuxNode(ResourceManager):
             (out, err), proc = execfuncs.lexec(command, 
                     user = self.get("username"), # still problem with localhost
                     sudo = sudo,
-                    stdin = stdin,
                     env = env)
         else:
             if with_lock:
+                # If the execute command is blocking, we don't want to keep
+                # the node lock. This lock is used to avoid race conditions
+                # when creating the ControlMaster sockets. A more elegant
+                # solution is needed.
                 with self._node_lock:
                     (out, err), proc = sshfuncs.rexec(
                         command, 
@@ -487,15 +493,12 @@ class LinuxNode(ResourceManager):
                         gw = self.get("gateway"),
                         agent = True,
                         sudo = sudo,
-                        stdin = stdin,
                         identity = self.get("identity"),
                         server_key = self.get("serverKey"),
                         env = env,
                         tty = tty,
                         forward_x11 = forward_x11,
-                        timeout = timeout,
                         retry = retry,
-                        err_on_timeout = err_on_timeout,
                         connect_timeout = connect_timeout,
                         persistent = persistent,
                         blocking = blocking, 
@@ -511,15 +514,12 @@ class LinuxNode(ResourceManager):
                     gw = self.get("gateway"),
                     agent = True,
                     sudo = sudo,
-                    stdin = stdin,
                     identity = self.get("identity"),
                     server_key = self.get("serverKey"),
                     env = env,
                     tty = tty,
                     forward_x11 = forward_x11,
-                    timeout = timeout,
                     retry = retry,
-                    err_on_timeout = err_on_timeout,
                     connect_timeout = connect_timeout,
                     persistent = persistent,
                     blocking = blocking, 
@@ -540,14 +540,13 @@ class LinuxNode(ResourceManager):
         self.debug("Running command '%s'" % command)
         
         if self.localhost:
-            (out, err), proc = execfuncs.lspawn(command, pidfile, 
-                    stdout = stdout, 
-                    stderr = stderr, 
-                    stdin = stdin, 
+            (out, err), proc = execfuncs.lspawn(command, pidfile,
                     home = home, 
                     create_home = create_home, 
-                    sudo = sudo,
-                    user = user) 
+                    stdin = stdin or '/dev/null',
+                    stdout = stdout or '/dev/null',
+                    stderr = stderr or '/dev/null',
+                    sudo = sudo) 
         else:
             with self._node_lock:
                 (out, err), proc = sshfuncs.rspawn(
@@ -555,9 +554,9 @@ class LinuxNode(ResourceManager):
                     pidfile = pidfile,
                     home = home,
                     create_home = create_home,
-                    stdin = stdin if stdin is not None else '/dev/null',
-                    stdout = stdout if stdout else '/dev/null',
-                    stderr = stderr if stderr else '/dev/null',
+                    stdin = stdin or '/dev/null',
+                    stdout = stdout or '/dev/null',
+                    stderr = stderr or '/dev/null',
                     sudo = sudo,
                     host = self.get("hostname"),
                     user = self.get("username"),
@@ -637,9 +636,8 @@ class LinuxNode(ResourceManager):
 
     def copy(self, src, dst):
         if self.localhost:
-            (out, err), proc = execfuncs.lcopy(source, dest, 
-                    recursive = True,
-                    strict_host_checking = False)
+            (out, err), proc = execfuncs.lcopy(src, dst, 
+                    recursive = True)
         else:
             with self._node_lock:
                 (out, err), proc = sshfuncs.rcopy(
@@ -654,14 +652,21 @@ class LinuxNode(ResourceManager):
 
         return (out, err), proc
 
-    def upload(self, src, dst, text = False, overwrite = True):
+    def upload(self, src, dst, text = False, overwrite = True,
+            raise_on_error = True):
         """ Copy content to destination
 
-           src  content to copy. Can be a local file, directory or a list of files
+        src  string with the content to copy. Can be:
+            - plain text
+            - a string with the path to a local file
+            - a string with a semi-colon separeted list of local files
+            - a string with a local directory
 
-           dst  destination path on the remote host (remote is always self.host)
+        dst  string with destination path on the remote host (remote is 
+            always self.host)
 
-           text src is text input, it must be stored into a temp file before uploading
+        text src is text input, it must be stored into a temp file before 
+        uploading
         """
         # If source is a string input 
         f = None
@@ -674,29 +679,50 @@ class LinuxNode(ResourceManager):
             src = f.name
 
         # If dst files should not be overwritten, check that the files do not
-        # exits already 
+        # exits already
+        if isinstance(src, str):
+            src = map(str.strip, src.split(";"))
+    
         if overwrite == False:
             src = self.filter_existing_files(src, dst)
             if not src:
-                return ("", ""), None 
+                return ("", ""), None
 
         if not self.localhost:
             # Build destination as <user>@<server>:<path>
             dst = "%s@%s:%s" % (self.get("username"), self.get("hostname"), dst)
 
-        result = self.copy(src, dst)
+        ((out, err), proc) = self.copy(src, dst)
 
         # clean up temp file
         if f:
             os.remove(f.name)
 
-        return result
+        if err:
+            msg = " Failed to upload files - src: %s dst: %s" %  (";".join(src), dst) 
+            self.error(msg, out, err)
+            
+            msg = "%s out: %s err: %s" % (msg, out, err)
+            if raise_on_error:
+                raise RuntimeError, msg
+
+        return ((out, err), proc)
 
-    def download(self, src, dst):
+    def download(self, src, dst, raise_on_error = True):
         if not self.localhost:
             # Build destination as <user>@<server>:<path>
             src = "%s@%s:%s" % (self.get("username"), self.get("hostname"), src)
-        return self.copy(src, dst)
+
+        ((out, err), proc) = self.copy(src, dst)
+
+        if err:
+            msg = " Failed to download files - src: %s dst: %s" %  (";".join(src), dst) 
+            self.error(msg, out, err)
+
+            if raise_on_error:
+                raise RuntimeError, msg
+
+        return ((out, err), proc)
 
     def install_packages_command(self, packages):
         command = ""
@@ -711,7 +737,8 @@ class LinuxNode(ResourceManager):
 
         return command
 
-    def install_packages(self, packages, home, run_home = None):
+    def install_packages(self, packages, home, run_home = None,
+            raise_on_error = True):
         """ Install packages in the Linux host.
 
         'home' is the directory to upload the package installation script.
@@ -728,11 +755,12 @@ class LinuxNode(ResourceManager):
             stdout = "instpkg_stdout", 
             stderr = "instpkg_stderr",
             overwrite = False,
-            raise_on_error = True)
+            raise_on_error = raise_on_error)
 
         return (out, err), proc 
 
-    def remove_packages(self, packages, home, run_home = None):
+    def remove_packages(self, packages, home, run_home = None,
+            raise_on_error = True):
         """ Uninstall packages from the Linux host.
 
         'home' is the directory to upload the package un-installation script.
@@ -756,18 +784,35 @@ class LinuxNode(ResourceManager):
             stdout = "rmpkg_stdout", 
             stderr = "rmpkg_stderr",
             overwrite = False,
-            raise_on_error = True)
+            raise_on_error = raise_on_error)
          
         return (out, err), proc 
 
-    def mkdir(self, path, clean = False):
+    def mkdir(self, paths, clean = False):
+        """ Paths is either a single remote directory path to create,
+        or a list of directories to create.
+        """
         if clean:
-            self.rmdir(path)
+            self.rmdir(paths)
 
-        return self.execute("mkdir -p %s" % path, with_lock = True)
+        if isinstance(paths, str):
+            paths = [paths]
 
-    def rmdir(self, path):
-        return self.execute("rm -rf %s" % path, with_lock = True)
+        cmd = " ; ".join(map(lambda path: "mkdir -p %s" % path, paths))
+
+        return self.execute(cmd, with_lock = True)
+
+    def rmdir(self, paths):
+        """ Paths is either a single remote directory path to delete,
+        or a list of directories to delete.
+        """
+
+        if isinstance(paths, str):
+            paths = [paths]
+
+        cmd = " ; ".join(map(lambda path: "rm -rf %s" % path, paths))
+
+        return self.execute(cmd, with_lock = True)
         
     def run_and_wait(self, command, home, 
             shfile = "cmd.sh",
@@ -780,7 +825,7 @@ class LinuxNode(ResourceManager):
             stderr = "stderr", 
             sudo = False,
             tty = False,
-            raise_on_error = False):
+            raise_on_error = True):
         """
         Uploads the 'command' to a bash script in the host.
         Then runs the script detached in background in the host, and
@@ -1034,8 +1079,8 @@ class LinuxNode(ResourceManager):
         """ Removes files that already exist in the Linux host from src list
         """
         # construct a dictionary with { dst: src }
-        dests = dict(map(lambda x: ( os.path.join(dst, os.path.basename(x) ),  x ), 
-            src.strip().split(" ") ) ) if src.strip().find(" ") != -1 else dict({dst: src})
+        dests = dict(map(lambda s: (os.path.join(dst, os.path.basename(s)), s), src)) \
+                    if len(src) > 1 else dict({dst: src[0]})
 
         command = []
         for d in dests.keys():
@@ -1050,7 +1095,7 @@ class LinuxNode(ResourceManager):
                 del dests[d]
 
         if not dests:
-            return ""
+            return []
 
-        return " ".join(dests.values())
+        return dests.values()
 
index 62bacd8..544b4d9 100644 (file)
@@ -34,84 +34,84 @@ class LinuxNPing(LinuxApplication):
             "Sets nping -c option. "
             "Stop after a given number of rounds. ",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         e = Attribute("e",
             "Sets nping -e option. "
             "Set the network interface to be used.",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         delay = Attribute("delay",
             "Sets nping --delay option. "
             "Delay between probes ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         rate = Attribute("rate",
             "Sets nping --rate option. "
             "Send probes at a given rate ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ttl = Attribute("ttl",
             "Sets nping --ttl option. "
             "Time To Live. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         p = Attribute("p",
             "Sets nping -p option. "
             "Target ports. ",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         tcp = Attribute("tcp",
             "Sets nping --tcp option. "
             "TCP mode. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         udp = Attribute("udp",
             "Sets nping --udp option. "
             "UDP mode. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         icmp = Attribute("icmp",
             "Sets nping --icmp option. "
             "ICMP mode. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         arp = Attribute("arp",
             "Sets nping --arp option. "
             "ARP mode. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         traceroute = Attribute("traceroute",
             "Sets nping --traceroute option. "
             "Traceroute mode. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         countinuous = Attribute("continuous",
             "Run nping in a while loop",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         print_timestamp = Attribute("printTimestamp",
             "Print timestamp before running nping",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         target = Attribute("target",
             "nping target host (host that will be pinged)",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(c)
         cls._register_attribute(e)
diff --git a/src/nepi/resources/linux/ns3/__init__.py b/src/nepi/resources/linux/ns3/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/nepi/resources/linux/ns3/dependencies/pygccxml-1.0.0.tar.gz b/src/nepi/resources/linux/ns3/dependencies/pygccxml-1.0.0.tar.gz
new file mode 100644 (file)
index 0000000..5e71694
Binary files /dev/null and b/src/nepi/resources/linux/ns3/dependencies/pygccxml-1.0.0.tar.gz differ
diff --git a/src/nepi/resources/linux/ns3/ns3client.py b/src/nepi/resources/linux/ns3/ns3client.py
new file mode 100644 (file)
index 0000000..882c1f3
--- /dev/null
@@ -0,0 +1,116 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+import base64
+import cPickle
+import errno
+import os
+import socket
+import time
+import weakref
+
+from optparse import OptionParser, SUPPRESS_HELP
+
+from nepi.resources.ns3.ns3client import NS3Client
+from nepi.resources.ns3.ns3server import NS3WrapperMessage
+
+class LinuxNS3Client(NS3Client):
+    def __init__(self, simulation):
+        super(LinuxNS3Client, self).__init__()
+        self._simulation = weakref.ref(simulation)
+
+        self._socat_proc = None
+
+    @property
+    def simulation(self):
+        return self._simulation()
+
+    def send_msg(self, msg_type, *args, **kwargs):
+        msg = [msg_type, args, kwargs]
+
+        def encode(item):
+            item = cPickle.dumps(item)
+            return base64.b64encode(item)
+
+        encoded = "|".join(map(encode, msg))
+
+        if self.simulation.node.get("hostname") in ['localhost', '127.0.0.1']:
+            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            sock.connect(self.simulation.remote_socket)
+            sock.send("%s\n" % encoded)
+            reply = sock.recv(1024)
+            sock.close()
+
+        else:
+            command = ( "python -c 'import socket;"
+                "sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM);"
+                "sock.connect(\"%(socket_addr)s\");"
+                "msg = \"%(encoded_message)s\\n\";"
+                "sock.send(msg);"
+                "reply = sock.recv(1024);"
+                "sock.close();"
+                "print reply'") % {
+                    "encoded_message": encoded,
+                    "socket_addr": self.simulation.remote_socket,
+                    }
+
+            (reply, err), proc = self.simulation.node.execute(command)
+
+            if (err and proc.poll()) or reply.strip() == "":
+                msg = " Couldn't connect to remote socket %s" % (
+                        self.simulation.remote_socket)
+                self.simulation.error(msg, reply, err)
+                raise RuntimeError(msg)
+                   
+        reply = cPickle.loads(base64.b64decode(reply))
+
+        return reply
+
+    def create(self, *args, **kwargs):
+        return self.send_msg(NS3WrapperMessage.CREATE, *args, **kwargs)
+
+    def factory(self, *args, **kwargs):
+        return self.send_msg(NS3WrapperMessage.FACTORY, *args, **kwargs)
+
+    def invoke(self, *args, **kwargs):
+        return self.send_msg(NS3WrapperMessage.INVOKE, *args, **kwargs)
+
+    def set(self, *args, **kwargs):
+        return self.send_msg(NS3WrapperMessage.SET, *args, **kwargs)
+
+    def get(self, *args, **kwargs):
+        return self.send_msg(NS3WrapperMessage.GET, *args, **kwargs)
+
+    def flush(self, *args, **kwargs):
+        return self.send_msg(NS3WrapperMessage.FLUSH, *args, **kwargs)
+
+    def start(self, *args, **kwargs):
+        return self.send_msg(NS3WrapperMessage.START, *args, **kwargs)
+
+    def stop(self, *args, **kwargs):
+        return self.send_msg(NS3WrapperMessage.STOP, *args, **kwargs)
+
+    def shutdown(self, *args, **kwargs):
+        try:
+            return self.send_msg(NS3WrapperMessage.SHUTDOWN, *args, **kwargs)
+        except:
+            pass
+
+        return None
+
diff --git a/src/nepi/resources/linux/ns3/ns3dceapplication.py b/src/nepi/resources/linux/ns3/ns3dceapplication.py
new file mode 100644 (file)
index 0000000..ca32b6f
--- /dev/null
@@ -0,0 +1,128 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import clsinit_copy, ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication
+
+@clsinit_copy
+class NS3LinuxDceApplication(NS3BaseDceApplication):
+    _rtype = "ns3::LinuxDceApplication"
+
+    @classmethod
+    def _register_attributes(cls):
+        sources = Attribute("sources",
+                "Path to tar.gz file with sources for the application execute in DCE. "
+                "Sources will be uploaded to ${SRC} and it is the responsibility of "
+                "the build instructions (in the build attribute) to copy the compiled "
+                "binaries to the ${BIN_DCE} directory",
+                flags = Flags.Design)
+
+        build = Attribute("build",
+                "Instructions to compile sources DCE-compatible way. "
+                "Note that sources will be uploaded to ${SRC} and the "
+                "build instructions are responsible for copying the "
+                "binaries to the ${BIN_DCE} directory. ",
+                flags = Flags.Design)
+
+        depends = Attribute("depends", 
+                "Space-separated list of packages required to run the application",
+                flags = Flags.Design)
+
+        files = Attribute("files", 
+                "Semi-colon separated list of 'key=value' pairs to set as "
+                "DCE files (AddFile). The key should be a path to a local file "
+                "and the key is the path to be set in DCE for that file" ,
+                flags = Flags.Design)
+
+        stdinfile = Attribute("stdinFile", 
+                "File to set as StdinFile. The value shoudl be either an empty "
+                "or a path to a local file ",
+                flags = Flags.Design)
+
+        starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            default = "+0.0ns",  
+            flags = Flags.Reserved | Flags.Construct)
+
+        stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            default = "+0.0ns",  
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(sources)
+        cls._register_attribute(build)
+        cls._register_attribute(depends)
+        cls._register_attribute(files)
+        cls._register_attribute(stoptime)
+        cls._register_attribute(starttime)
+        cls._register_attribute(stdinfile)
+
+    def _instantiate_object(self):
+        command = []
+
+        # Install package dependencies required to run the binary 
+        depends = self.get("depends")
+        if depends:
+            dcmd = self.simulation.install_dependencies(depends = depends)
+            if dcmd:
+                command.append(dcmd)
+       
+        # Upload sources to generate the binary
+        sources = self.get("sources")
+        if sources:
+            scmd = self.simulation.upload_extra_sources(sources = sources)
+            if scmd:
+                command.append(scmd)
+                
+        # Upload files to the remote machine. These files will 
+        # be added to the DceApplication by invoking dce.AddFile()
+        files = self.get("files") or ""
+        if files:
+            upfiles = []
+            for files in map(str.strip, files.split(";")):
+                localpath, dcepath = env.split("=")
+                upfiles.append(localpath)
+
+            if upfiles:
+                fcmd = self.siumlation.upload_files(files = upfiles)
+                if fcmd:
+                    command.append(fcmd)
+
+        # Upload files to the remote machine. These files will 
+        # be added to the DceApplication by invoking dce.AddFile()
+        stdinfile = self.get("stdinFile")
+        if stdinfile and stdinfile != "":
+            stdincmd = self.siumlation.upload_files(files = stdinfile)
+            if stdincmd:
+                command.append(stdincmd)
+
+
+        # Upload instructions to build the binary
+        build = self.get("build")
+        if build:
+            bcmd = self.simulation.build(build = build)
+            if bcmd:
+                command.append(bcmd)
+
+        if command:
+            deploy_command = ";".join(command)
+            prefix = "%d_deploy" % self.guid 
+            self.simulation.execute_deploy_command(deploy_command, prefix=prefix)
+
diff --git a/src/nepi/resources/linux/ns3/ns3simulation.py b/src/nepi/resources/linux/ns3/ns3simulation.py
new file mode 100644 (file)
index 0000000..9e1ee51
--- /dev/null
@@ -0,0 +1,588 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow, tdiffsec
+from nepi.resources.ns3.ns3simulation import NS3Simulation
+from nepi.resources.ns3.ns3wrapper import SIMULATOR_UUID, GLOBAL_VALUE_UUID, \
+        IPV4_GLOBAL_ROUTING_HELPER_UUID
+from nepi.resources.linux.ns3.ns3client import LinuxNS3Client
+
+import os
+import time
+import threading
+
+@clsinit_copy
+class LinuxNS3Simulation(LinuxApplication, NS3Simulation):
+    _rtype = "LinuxNS3Simulation"
+
+    @classmethod
+    def _register_attributes(cls):
+        impl_type = Attribute("simulatorImplementationType",
+                "The object class to use as the simulator implementation",
+            allowed = ["ns3::DefaultSimulatorImpl", "ns3::RealtimeSimulatorImpl"],
+            default = "ns3::DefaultSimulatorImpl",
+            type = Types.Enumerate,
+            flags = Flags.Design)
+
+        sched_type = Attribute("schedulerType",
+                "The object class to use as the scheduler implementation",
+                allowed = ["ns3::MapScheduler",
+                            "ns3::ListScheduler",
+                            "ns3::HeapScheduler",
+                            "ns3::MapScheduler",
+                            "ns3::CalendarScheduler"
+                    ],
+            default = "ns3::MapScheduler",
+            type = Types.Enumerate,
+            flags = Flags.Design)
+
+        check_sum = Attribute("checksumEnabled",
+                "A global switch to enable all checksums for all protocols",
+            default = False,
+            type = Types.Bool,
+            flags = Flags.Design)
+
+        ns_log = Attribute("nsLog",
+            "NS_LOG environment variable. " \
+                    " Will only generate output if ns-3 is compiled in DEBUG mode. ",
+            flags = Flags.Design)
+
+        verbose = Attribute("verbose",
+            "True to output debugging info from the ns3 client-server communication",
+            type = Types.Bool,
+            flags = Flags.Design)
+
+        build_mode = Attribute("buildMode",
+            "Mode used to build ns-3 with waf. One if: debug, release, oprimized ",
+            default = "optimized", 
+            allowed = ["debug", "release", "optimized"],
+            type = Types.Enumerate,
+            flags = Flags.Design)
+
+        ns3_version = Attribute("ns3Version",
+            "Version of ns-3 to install from nsam repo",
+            #default = "ns-3.19", 
+            default = "ns-3-dev", 
+            flags = Flags.Design)
+
+        enable_dce = Attribute("enableDCE",
+            "Install DCE source code",
+            default = False, 
+            type = Types.Bool,
+            flags = Flags.Design)
+
+        pybindgen_version = Attribute("pybindgenVersion",
+            "Version of pybindgen to install from bazar repo",
+            default = "868", 
+            flags = Flags.Design)
+
+        populate_routing_tables = Attribute("populateRoutingTables",
+            "Invokes  Ipv4GlobalRoutingHelper.PopulateRoutingTables() ",
+            default = False,
+            type = Types.Bool,
+            flags = Flags.Design)
+
+        cls._register_attribute(impl_type)
+        cls._register_attribute(sched_type)
+        cls._register_attribute(check_sum)
+        cls._register_attribute(ns_log)
+        cls._register_attribute(verbose)
+        cls._register_attribute(build_mode)
+        cls._register_attribute(ns3_version)
+        cls._register_attribute(pybindgen_version)
+        cls._register_attribute(populate_routing_tables)
+        cls._register_attribute(enable_dce)
+
+    def __init__(self, ec, guid):
+        LinuxApplication.__init__(self, ec, guid)
+        NS3Simulation.__init__(self)
+
+        self._client = None
+        self._home = "ns3-simu-%s" % self.guid
+        self._socket_name = "ns3-%s.sock" % os.urandom(4).encode('hex')
+        self._dce_manager_helper_uuid = None
+        self._dce_application_helper_uuid = None
+        
+        # Lock used to synchronize usage of DceManagerHelper 
+        self.dce_manager_lock = threading.Lock()
+        # Lock used to synchronize usage of DceApplicationHelper
+        self.dce_application_lock = threading.Lock()
+
+    @property
+    def socket_name(self):
+        return self._socket_name
+
+    @property
+    def remote_socket(self):
+        return os.path.join(self.run_home, self.socket_name)
+
+    @property
+    def dce_manager_helper_uuid(self):
+        return self._dce_manager_helper_uuid
+
+    @property
+    def dce_application_helper_uuid(self):
+        return self._dce_application_helper_uuid
+
+    @property
+    def ns3_build_home(self):
+        return os.path.join(self.node.bin_dir, "ns-3", self.get("ns3Version"), 
+                self.get("buildMode"), "build")
+
+    def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0):
+        self._client.flush() 
+        return LinuxApplication.trace(self, name, attr, block, offset)
+
+    def upload_sources(self):
+        self.node.mkdir(os.path.join(self.node.src_dir, "ns3wrapper"))
+
+        # upload ns3 wrapper python script
+        ns3_wrapper = os.path.join(os.path.dirname(__file__), "..", "..", "ns3", 
+                "ns3wrapper.py")
+
+        self.node.upload(ns3_wrapper,
+                os.path.join(self.node.src_dir, "ns3wrapper", "ns3wrapper.py"),
+                overwrite = False)
+
+        # upload ns3_server python script
+        ns3_server = os.path.join(os.path.dirname(__file__), "..", "..", "ns3",
+                "ns3server.py")
+
+        self.node.upload(ns3_server,
+                os.path.join(self.node.src_dir, "ns3wrapper", "ns3server.py"),
+                overwrite = False)
+
+        if self.node.use_rpm:
+            # upload pygccxml sources
+            pygccxml_tar = os.path.join(os.path.dirname(__file__), "dependencies",
+                    "%s.tar.gz" % self.pygccxml_version)
+
+            self.node.upload(pygccxml_tar,
+                    os.path.join(self.node.src_dir, "%s.tar.gz" % self.pygccxml_version),
+                    overwrite = False)
+
+        # Upload user defined ns-3 sources
+        self.node.mkdir(os.path.join(self.node.src_dir, "ns-3"))
+        src_dir = os.path.join(self.node.src_dir, "ns-3")
+
+        super(LinuxNS3Simulation, self).upload_sources(src_dir = src_dir)
+    
+    def upload_extra_sources(self, sources = None, src_dir = None):
+        return super(LinuxNS3Simulation, self).upload_sources(
+                sources = sources, 
+                src_dir = src_dir)
+
+    def upload_start_command(self):
+        command = self.get("command")
+        env = self.get("env")
+
+        # We want to make sure the ccnd is running
+        # before the experiment starts.
+        # Run the command as a bash script in background,
+        # in the host ( but wait until the command has
+        # finished to continue )
+        env = self.replace_paths(env)
+        command = self.replace_paths(command)
+
+        shfile = os.path.join(self.app_home, "start.sh")
+        self.node.upload_command(command, 
+                    shfile = shfile,
+                    env = env,
+                    overwrite = True)
+
+        # Run the ns3wrapper 
+        self._run_in_background()
+
+    def configure(self):
+        if self.has_changed("simulatorImplementationType"):
+            simu_type = self.get("simulatorImplementationType")
+            stype = self.create("StringValue", simu_type)
+            self.invoke(GLOBAL_VALUE_UUID, "Bind", "SimulatorImplementationType", stype)
+
+        if self.has_changed("checksumEnabled"):
+            check_sum = self.get("checksumEnabled")
+            btrue = self.create("BooleanValue", check_sum)    
+            self.invoke(GLOBAL_VALUE_UUID, "Bind", "ChecksumEnabled", btrue)
+        
+        if self.has_changed("schedulerType"):
+            sched_type = self.get("schedulerType")
+            stype = self.create("StringValue", sched_type)
+            self.invoke(GLOBAL_VALUE_UUID, "Bind", "SchedulerType", btrue)
+        
+        if self.get("enableDCE"):
+            self._dce_manager_helper_uuid = self.create("DceManagerHelper")
+            self._dce_application_helper_uuid = self.create("DceApplicationHelper")
+
+    def do_deploy(self):
+        if not self.node or self.node.state < ResourceState.READY:
+            self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state )
+            
+            # ccnd needs to wait until node is deployed and running
+            self.ec.schedule(reschedule_delay, self.deploy)
+        else:
+            if not self.get("command"):
+                self.set("command", self._start_command)
+            
+            if not self.get("depends"):
+                self.set("depends", self._dependencies)
+
+            if self.get("sources"):
+                sources = self.get("sources")
+                source = sources.split(" ")[0]
+                basename = os.path.basename(source)
+                version = ( basename.strip().replace(".tar.gz", "")
+                    .replace(".tar","")
+                    .replace(".gz","")
+                    .replace(".zip","") )
+
+                self.set("ns3Version", version)
+                self.set("sources", source)
+
+            if not self.get("build"):
+                self.set("build", self._build)
+
+            if not self.get("install"):
+                self.set("install", self._install)
+
+            if not self.get("env"):
+                self.set("env", self._environment)
+
+            self.do_discover()
+            self.do_provision()
+
+            # Create client
+            self._client = LinuxNS3Client(self)
+
+            self.configure()
+            
+            self.set_ready()
+
+    def do_start(self):
+        """ Starts simulation execution
+
+        """
+        self.info("Starting")
+
+        if self.state == ResourceState.READY:
+            if self.get("populateRoutingTables") == True:
+                self.invoke(IPV4_GLOBAL_ROUTING_HELPER_UUID, "PopulateRoutingTables")
+
+            self._client.start() 
+
+            self.set_started()
+        else:
+            msg = " Failed to execute command '%s'" % command
+            self.error(msg, out, err)
+            raise RuntimeError, msg
+
+    def do_stop(self):
+        """ Stops simulation execution
+
+        """
+        if self.state == ResourceState.STARTED:
+            self._client.stop() 
+            self.set_stopped()
+
+    def do_release(self):
+        self.info("Releasing resource")
+
+        tear_down = self.get("tearDown")
+        if tear_down:
+            self.node.execute(tear_down)
+
+        self.do_stop()
+        self._client.shutdown()
+        LinuxApplication.do_stop(self)
+        
+        super(LinuxApplication, self).do_release()
+
+    @property
+    def _start_command(self):
+        command = [] 
+
+        command.append("PYTHONPATH=$PYTHONPATH:${SRC}/ns3wrapper/")
+        
+        command.append("python ${SRC}/ns3wrapper/ns3server.py -S %s" % \
+                os.path.basename(self.remote_socket) )
+
+        ns_log = self.get("nsLog")
+        if ns_log:
+            command.append("-L '%s'" % ns_log)
+
+        if self.get("verbose"):
+            command.append("-v")
+
+        command = " ".join(command)
+        return command
+
+    @property
+    def _dependencies(self):
+        if self.node.use_rpm:
+            return ( " gcc gcc-c++ python python-devel mercurial bzr tcpdump socat gccxml unzip")
+        elif self.node.use_deb:
+            return ( " gcc g++ python python-dev mercurial bzr tcpdump socat gccxml python-pygccxml unzip")
+        return ""
+
+    @property
+    def ns3_repo(self):
+        return "http://code.nsnam.org"
+
+    @property
+    def pygccxml_version(self):
+        return "pygccxml-1.0.0"
+
+    @property
+    def dce_repo(self):
+        #return "http://code.nsnam.org/ns-3-dce"
+        return "http://code.nsnam.org/epmancini/ns-3-dce"
+
+    @property
+    def _build(self):
+        # If the user defined local sources for ns-3, we uncompress the sources
+        # on the remote sources directory. Else we clone ns-3 from the official repo.
+        source = self.get("sources")
+        if not source:
+            clone_ns3_cmd = "hg clone %(ns3_repo)s/%(ns3_version)s ${SRC}/ns-3/%(ns3_version)s" \
+                    % {
+                        'ns3_version': self.get("ns3Version"),
+                        'ns3_repo':  self.ns3_repo,       
+                      }
+        else:
+            if source.find(".tar.gz") > -1:
+                clone_ns3_cmd = ( 
+                            "tar xzf ${SRC}/ns-3/%(basename)s " 
+                            " --strip-components=1 -C ${SRC}/ns-3/%(ns3_version)s "
+                            ) % {
+                                'basename': os.path.basename(source),
+                                'ns3_version': self.get("ns3Version"),
+                                }
+            elif source.find(".tar") > -1:
+                clone_ns3_cmd = ( 
+                            "tar xf ${SRC}/ns-3/%(basename)s " 
+                            " --strip-components=1 -C ${SRC}/ns-3/%(ns3_version)s "
+                            ) % {
+                                'basename': os.path.basename(source),
+                                'ns3_version': self.get("ns3Version"),
+                                }
+            elif source.find(".zip") > -1:
+                basename = os.path.basename(source)
+                bare_basename = basename.replace(".zip", "") \
+                        .replace(".tar", "") \
+                        .replace(".tar.gz", "")
+
+                clone_ns3_cmd = ( 
+                            "unzip ${SRC}/ns-3/%(basename)s && "
+                            "mv ${SRC}/ns-3/%(bare_basename)s ${SRC}/ns-3/%(ns3_version)s "
+                            ) % {
+                                'bare_basename': basename_name,
+                                'basename': basename,
+                                'ns3_version': self.get("ns3Version"),
+                                }
+
+        clone_dce_cmd = " echo 'DCE will not be built' "
+        if self.get("enableDCE"):
+            clone_dce_cmd = (
+                        # DCE installation
+                        # Test if dce is alredy installed
+                        " ( "
+                        "  ( "
+                        "    ( test -d ${SRC}/dce/ns-3-dce ) "
+                        "   && echo 'dce binaries found, nothing to do'"
+                        "  ) "
+                        " ) "
+                        "  || " 
+                        # Get dce source code
+                        " ( "
+                        "   mkdir -p ${SRC}/dce && "
+                        "   hg clone %(dce_repo)s ${SRC}/dce/ns-3-dce"
+                        " ) "
+                     ) % {
+                            'dce_repo': self.dce_repo
+                         }
+
+
+        return (
+                # NS3 installation
+                "( "
+                " ( "
+                # Test if ns-3 is alredy installed
+                "  ((( test -d ${SRC}/ns-3/%(ns3_version)s ) || "
+                "    ( test -d ${NS3BINDINGS:='None'} && test -d ${NS3LIBRARIES:='None'})) "
+                "  && echo 'ns-3 binaries found, nothing to do' )"
+                " ) "
+                "  || " 
+                # If not, install ns-3 and its dependencies
+                " (   "
+                # Install pygccxml
+                "   (   "
+                "     ( "
+                "       python -c 'import pygccxml' && "
+                "       echo 'pygccxml not found' "
+                "     ) "
+                "      || "
+                "     ( "
+                "       tar xf ${SRC}/%(pygccxml_version)s.tar.gz -C ${SRC} && "
+                "       cd ${SRC}/%(pygccxml_version)s && "
+                "       python setup.py build && "
+                "       sudo -S python setup.py install "
+                "     ) "
+                "   ) " 
+                # Install pybindgen
+                "  && "
+                "   (   "
+                "     ( "
+                "       test -d ${SRC}/pybindgen/%(pybindgen_version)s && "
+                "       echo 'binaries found, nothing to do' "
+                "     ) "
+                "      || "
+                # If not, clone and build
+                "      ( cd ${SRC} && "
+                "        mkdir -p ${SRC}/pybindgen && "
+                "        bzr checkout lp:pybindgen -r %(pybindgen_version)s ${SRC}/pybindgen/%(pybindgen_version)s && "
+                "        cd ${SRC}/pybindgen/%(pybindgen_version)s && "
+                "        ./waf configure && "
+                "        ./waf "
+                "      ) "
+                "   ) " 
+                " && "
+                # Get ns-3 source code
+                "  ( "
+                "     mkdir -p ${SRC}/ns-3/%(ns3_version)s && "
+                "     %(clone_ns3_cmd)s "
+                "  ) "
+                " ) "
+                ") "
+                " && "
+                "( "
+                "   %(clone_dce_cmd)s "
+                ") "
+             ) % { 
+                    'ns3_version': self.get("ns3Version"),
+                    'pybindgen_version': self.get("pybindgenVersion"),
+                    'pygccxml_version': self.pygccxml_version,
+                    'clone_ns3_cmd': clone_ns3_cmd,
+                    'clone_dce_cmd': clone_dce_cmd,
+                 }
+
+    @property
+    def _install(self):
+        install_dce_cmd = " echo 'DCE will not be installed' "
+        if self.get("enableDCE"):
+            install_dce_cmd = (
+                        " ( "
+                        "   ((test -d %(ns3_build_home)s/bin_dce ) && "
+                        "    echo 'dce binaries found, nothing to do' )"
+                        " ) "
+                        " ||" 
+                        " (   "
+                         # If not, copy ns-3 build to bin
+                        "  cd ${SRC}/dce/ns-3-dce && "
+                        "  ./waf configure %(enable_opt)s --with-pybindgen=${SRC}/pybindgen/%(pybindgen_version)s "
+                        "  --prefix=%(ns3_build_home)s --with-ns3=%(ns3_build_home)s && "
+                        "  ./waf build && "
+                        "  ./waf install && "
+                        "  mv %(ns3_build_home)s/lib*/python*/site-packages/ns/dce.so %(ns3_build_home)s/lib/python/site-packages/ns/ "
+                        " )"
+                ) % { 
+                    'ns3_version': self.get("ns3Version"),
+                    'pybindgen_version': self.get("pybindgenVersion"),
+                    'ns3_build_home': self.ns3_build_home,
+                    'build_mode': self.get("buildMode"),
+                    'enable_opt': "--enable-opt" if  self.get("buildMode") == "optimized" else ""
+                    }
+
+        return (
+                 # Test if ns-3 is alredy installed
+                "("
+                " ( "
+                "  ( ( (test -d %(ns3_build_home)s/lib ) || "
+                "    (test -d ${NS3BINDINGS:='None'} && test -d ${NS3LIBRARIES:='None'}) ) && "
+                "    echo 'binaries found, nothing to do' )"
+                " ) "
+                " ||" 
+                " (   "
+                 # If not, copy ns-3 build to bin
+                "  mkdir -p %(ns3_build_home)s && "
+                "  cd ${SRC}/ns-3/%(ns3_version)s && "
+                "  ./waf configure -d %(build_mode)s --with-pybindgen=${SRC}/pybindgen/%(pybindgen_version)s "
+                "  --prefix=%(ns3_build_home)s && "
+                "  ./waf build && "
+                "  ./waf install && "
+                "  mv %(ns3_build_home)s/lib*/python* %(ns3_build_home)s/lib/python "
+                " )"
+                ") "
+                " && "
+                "( "
+                "   %(install_dce_cmd)s "
+                ") "
+              ) % { 
+                    'ns3_version': self.get("ns3Version"),
+                    'pybindgen_version': self.get("pybindgenVersion"),
+                    'build_mode': self.get("buildMode"),
+                    'ns3_build_home': self.ns3_build_home,
+                    'install_dce_cmd': install_dce_cmd
+                 }
+
+    @property
+    def _environment(self):
+        env = []
+        env.append("PYTHONPATH=$PYTHONPATH:${NS3BINDINGS:=%(ns3_build_home)s/lib/python/site-packages}" % { 
+                    'ns3_build_home': self.ns3_build_home
+                 })
+        # If NS3LIBRARIES is defined and not empty, assign its value, 
+        # if not assign ns3_build_home/lib/ to NS3LIBRARIES and LD_LIBARY_PATH
+        env.append("LD_LIBRARY_PATH=${NS3LIBRARIES:=%(ns3_build_home)s/lib}" % { 
+                    'ns3_build_home': self.ns3_build_home
+                 })
+        env.append("DCE_PATH=$NS3LIBRARIES/../bin_dce")
+        env.append("DCE_ROOT=$NS3LIBRARIES/..")
+
+        return " ".join(env) 
+
+    def replace_paths(self, command):
+        """
+        Replace all special path tags with shell-escaped actual paths.
+        """
+        return ( command
+            .replace("${USR}", self.node.usr_dir)
+            .replace("${LIB}", self.node.lib_dir)
+            .replace("${BIN}", self.node.bin_dir)
+            .replace("${SRC}", self.node.src_dir)
+            .replace("${SHARE}", self.node.share_dir)
+            .replace("${EXP}", self.node.exp_dir)
+            .replace("${EXP_HOME}", self.node.exp_home)
+            .replace("${APP_HOME}", self.app_home)
+            .replace("${RUN_HOME}", self.run_home)
+            .replace("${NODE_HOME}", self.node.node_home)
+            .replace("${HOME}", self.node.home_dir)
+            # If NS3LIBRARIES is defined and not empty, use that value, 
+            # if not use ns3_build_home/lib/
+            .replace("${BIN_DCE}", "${NS3LIBRARIES-%s/lib/}../bin_dce" % \
+                    self.ns3_build_home)
+            )
+
+    def valid_connection(self, guid):
+        # TODO: Validate!
+        return True
+
index 6db0a8d..a3df579 100644 (file)
@@ -34,56 +34,56 @@ class LinuxPing(LinuxApplication):
             "Sets ping -c option. Determines the number of ECHO_REQUEST "
             "packates to send before stopping.",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         mark = Attribute("mark",
             "Sets ping -m option. Uses 'mark' to tag outgoing packets. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         interval = Attribute("interval",
             "Sets ping -i option. Leaves interval seconds between "
             "successive ECHO_REUQEST packets. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         address = Attribute("address",
             "Sets ping -I option. Sets ECHO_REQUEST packets souce address "
             "to the specified interface address ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         preload = Attribute("preload",
             "Sets ping -l option. Sends preload amount of packets "
             "without waiting for a reply ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         numeric = Attribute("numeric",
             "Sets ping -n option. Disables resolution of host addresses into "
             "symbolic names. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         pattern = Attribute("pattern",
             "Sets ping -p option. Species a up to 16 ''pad'' bytes to fill "
             "out sent packets. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         printtmp = Attribute("printTimestamp",
             "Sets ping -D option. Prints timestamp befor each line as: "
             "unix time + microseconds as in gettimeofday ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         tos = Attribute("tos",
             "Sets ping -Q option. Sets Quality of Service related bits in ICMP "
             "datagrams. tos can be either a decimal or hexadecime number ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         quiet = Attribute("quiet",
             "Sets ping -q option. Disables ping standard output ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         rec_route = Attribute("recordRoute",
             "Sets ping -R option. Includes the RECORD_ROUTE option in the "
@@ -91,37 +91,37 @@ class LinuxPing(LinuxApplication):
             "ping standard output.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         route_bypass = Attribute("routeBypass",
             "Sets ping -r option. Bypasses normal routing tables and sends "
             "ECHO REQUEST packets directly yo a host on an attached interface. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         packetsize = Attribute("packetSize",
             "Sets ping -s option. Specifies the number of data bytes to be "
             "sent. Defaults to 56. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         sendbuff = Attribute("sendBuff",
             "Sets ping -S option. Specifies the number of packets to buffer. "
             "Defaults to one. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ttl = Attribute("ttl",
             "Sets ping -t option. Specifies the IP Time to Live for the "
             "packets. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         timestamp = Attribute("timestamp",
             "Sets ping -T option. Sets special IP timestamp options. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         hint = Attribute("hint",
             "Sets ping -M option. Selects Path MTU Discovery strategy. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         full_latency = Attribute("fullLatency",
             "Sets ping -U option. Calculates round trip time taking into "
@@ -129,32 +129,32 @@ class LinuxPing(LinuxApplication):
             "network round trip time. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         verbose = Attribute("verbose",
             "Sets ping -v option. Verbose output. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         flood = Attribute("flood",
             "Sets ping -f option. Flood ping. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         deadline = Attribute("deadline",
             "Sets ping -w option. Specify a timeout, in seconds, before ping "
             "exits regardless of how many packets have been sent or received.",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         timeout = Attribute("timeout",
             "Sets ping -W option. Time to wait for a respone in seconds .",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         target = Attribute("target",
             "The host to ping .",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(count)
         cls._register_attribute(mark)
index 12d11a2..761c03e 100644 (file)
@@ -35,25 +35,25 @@ class LinuxTcpdump(LinuxApplication):
             "Prints each packet (minus its link level header) in ASCII.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         b = Attribute("b",
             "Sets tcpdump -b option. "
             "Prints the AS number in BGP packets in ASDOT notation. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         B = Attribute("B",
             "Sets tcpdump -B option. "
             "Sets the operaing system capture buffer size in untils of "
             "KiB (1024 bytes).",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         c = Attribute("c",
             "Sets tcpdump -c option. "
             "Exists after receiving count packets.",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         C = Attribute("C",
             "Sets tcpdump -C option. "
@@ -63,7 +63,7 @@ class LinuxTcpdump(LinuxApplication):
             "Savefiles after the first savefile will have the name specified "
             "with the -w with a number after it, starting at 1 and continuing "
             "upward. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         d = Attribute("d",
             "Sets tcpdump -d option. "
@@ -71,14 +71,14 @@ class LinuxTcpdump(LinuxApplication):
             "to standard output and stop.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         dd = Attribute("dd",
             "Sets tcpdump -dd option. "
             "Dump packet-matching code as a C program fragment. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ddd = Attribute("ddd",
             "Sets tcpdump -ddd option. "
@@ -86,7 +86,7 @@ class LinuxTcpdump(LinuxApplication):
             "(preceded with a count).",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         D = Attribute("D",
             "Sets tcpdump -D option. "
@@ -94,19 +94,19 @@ class LinuxTcpdump(LinuxApplication):
             "and on which tcpdump can capture packets. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         e = Attribute("e",
             "Sets tcpdump -e option. "
             "Print the link-level header on each dump line.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         F =  Attribute("F",
             "Sets tcpdump -F option. "
             "Use file as input for the filter expression.",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         G =  Attribute("G",
             "Sets tcpdump -G option. "
@@ -114,14 +114,14 @@ class LinuxTcpdump(LinuxApplication):
             "option every rotate_seconds seconds. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         i =  Attribute("i",
             "Sets tcpdump -i option. "
             "Listen on interface.  If unspecified, tcpdump searches the "
             "system interface list for the lowest  numbered, configured "
             "up interface (excluding loopback). ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         I =  Attribute("I",
             "Sets tcpdump -I option. "
@@ -130,7 +130,7 @@ class LinuxTcpdump(LinuxApplication):
             "operating systems. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         j = Attribute("j",
             "Sets tcpdump -j option. "
@@ -138,21 +138,21 @@ class LinuxTcpdump(LinuxApplication):
             "The names to use for the time stamp types are given in "
             "pcap-tstamp-type(7); not all the types listed there will "
             "necessarily be valid for any given interface.",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         K = Attribute("K",
             "Sets tcpdump -K option. "
             "Don't attempt to verify IP, TCP, or UDP checksums. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         l = Attribute("l",
             "Sets tcpdump -l option. "
             "Make stdout line buffered. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         U = Attribute("U",
             "Sets tcpdump -U option. "
@@ -161,7 +161,7 @@ class LinuxTcpdump(LinuxApplication):
             "at the end of each packet. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         n = Attribute("n",
             "Sets tcpdump -n option. "
@@ -169,7 +169,7 @@ class LinuxTcpdump(LinuxApplication):
             "etc.) to names.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         N = Attribute("N",
             "Sets tcpdump -N option. "
@@ -178,20 +178,20 @@ class LinuxTcpdump(LinuxApplication):
             "instead of ``nic.ddn.mil''.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         S = Attribute("S",
             "Sets tcpdump -S option. "
             "Print absolute, rather than relative, TCP sequence numbers.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         s = Attribute("s",
             "Sets tcpdump -s option. "
             "Snarf  snaplen bytes of data from each packet rather than "
             "the default of 65535 bytes. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         T = Attribute("T",
             "Sets tcpdump -T option. "
@@ -203,21 +203,21 @@ class LinuxTcpdump(LinuxApplication):
              "protocol), snmp (Simple Network Management Protocol), tftp "
              "(Trivial  File Transfer Protocol), vat (Visual Audio Tool), "
              "and wb (distributed White Board).",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         t = Attribute("t",
             "Sets tcpdump -t option. "
             "Don't print a timestamp on each dump line.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         tt = Attribute("tt",
             "Sets tcpdump -tt option. "
             "Print an unformatted timestamp on each dump line. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ttt = Attribute("ttt",
             "Sets tcpdump -ttt option. "
@@ -225,7 +225,7 @@ class LinuxTcpdump(LinuxApplication):
             "and previous line on each dump line.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         tttt = Attribute("tttt",
             "Sets tcpdump -tttt option. "
@@ -233,7 +233,7 @@ class LinuxTcpdump(LinuxApplication):
             "each dump line. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         ttttt = Attribute("ttttt",
             "Sets tcpdump -ttttt option. "
@@ -241,7 +241,7 @@ class LinuxTcpdump(LinuxApplication):
             "first line on each dump line.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         v = Attribute("v",
             "Sets tcpdump -v option. "
@@ -249,21 +249,21 @@ class LinuxTcpdump(LinuxApplication):
             "verbose output. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         vv = Attribute("vv",
             "Sets tcpdump -vv option. "
             "Even  more  verbose  output. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         vvv = Attribute("vvv",
             "Sets tcpdump -vv option. "
             "Even  more  verbose  output. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         w = Attribute("w",
             "Sets tcpdump -w option. "
@@ -271,11 +271,11 @@ class LinuxTcpdump(LinuxApplication):
             "and printing them out.",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         expression = Attribute("expression",
             "selects  which packets will be dumped.",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(A)
         cls._register_attribute(b)
index 99eea6b..3c3310a 100644 (file)
@@ -18,7 +18,7 @@
 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
 
 from nepi.execution.attribute import Attribute, Flags, Types
-from nepi.execution.resource import clsinit_copy, failtrap 
+from nepi.execution.resource import clsinit_copy 
 from nepi.resources.linux.application import LinuxApplication
 from nepi.util.timefuncs import tnow
 
@@ -35,13 +35,13 @@ class LinuxTraceroute(LinuxApplication):
             "Run traceroute in a while loop",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         print_timestamp = Attribute("printTimestamp",
             "Print timestamp before running traceroute",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         use_ip = Attribute("useIP",
             "Use the IP address instead of the host domain name. "
@@ -49,11 +49,11 @@ class LinuxTraceroute(LinuxApplication):
             "frequently",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         target = Attribute("target",
             "Traceroute target host (host that will be pinged)",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(countinuous)
         cls._register_attribute(print_timestamp)
@@ -64,15 +64,14 @@ class LinuxTraceroute(LinuxApplication):
         super(LinuxTraceroute, self).__init__(ec, guid)
         self._home = "traceroute-%s" % self.guid
 
-    @failtrap
-    def deploy(self):
+    def do_deploy(self):
         if not self.get("command"):
             self.set("command", self._start_command)
 
         if not self.get("depends"):
             self.set("depends", "traceroute")
 
-        super(LinuxTraceroute, self).deploy()
+        super(LinuxTraceroute, self).do_deploy()
 
     @property
     def _start_command(self):
index 76c5914..46accbc 100644 (file)
@@ -40,103 +40,103 @@ class LinuxUdpTest(LinuxApplication):
             "Runs in server mode. ",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         p = Attribute("p",
             "Port to listen to in server mode, or to connect to in client mode. "
             "Defaults to 5678. ",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         a = Attribute("a",
             "Client option. Perform UDP Round Trip Time (latency) ",
             type = Types.Bool,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         A = Attribute("A",
             "Client option. "
             "Message size for UDP RTT test. "
             "UDP RTT (latency) test with specified message size.",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         b = Attribute("b",
             "Client option. "
             "Client UDP buffer size in bytes. Using system default "
             "value if not defined.",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         B = Attribute("B",
             "Client option. "
             "Server UDP buffer size in bytes. The same as cleint's by default.",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         c = Attribute("c",
             "Client option. "
             "CPU log option. Tracing system info during the test. "
             "Only available when output is defined. ",
             type = Types.Bool,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         d = Attribute("d",
             "Client option. "
             "Data size of each read/write in bytes. The same as packet size "
             "by default.",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         e = Attribute("e",
             "Client option. "
             "Exponential test (data size of each sending increasing from 1 "
             "byte to packet size). ",
             type = Types.Bool,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         g = Attribute("g",
             "Client option. "
             "UDP traffic generator (Keep sending data to a host). "
             "Work without server's support.",
             type = Types.Bool,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         target = Attribute("target",
             "Client option. "
             "Hostname or IP address of UDP server. Must be specified.",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         i = Attribute("i",
             "Client option. "
             "Bidirectional UDP throuhgput test. Default is unidirection "
             "stream test. ",
             type = Types.Bool,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         l = Attribute("l",
             "Client option. "
             "UDP datagram (packet) size in bytes ( < udp-buffer-szie ). "
             "1460 by default.",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         m = Attribute("m",
             "Client option. "
             "Total message size in bytes. 1048576 by default.",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         o = Attribute("o",
             "Client option. "
             "Output file name. ",
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         P = Attribute("P",
             "Client option. "
             "Write the plot file for gnuplot. Only enable when the output "
             "is specified. ",
             type = Types.Bool,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         q = Attribute("q",
             "Client option. "
@@ -152,38 +152,38 @@ class LinuxUdpTest(LinuxApplication):
             "is specified. ",
             type = Types.Enumerate,
             allowed = ["1", "2", "3", "4", "5", "6"],
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         r = Attribute("r",
             "Client option. "
             "Repetition of tests. 10 by default. ",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         t = Attribute("t",
             "Client option. "
             "Test time constraint in seconds. 5 by default. ",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         T = Attribute("T",
             "Client option. "
             "Throughput constraint for UDP generator or throughput "
             "test. Unlimited by default. ",
             type = Types.Integer,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         continuous = Attribute("continuous",
             "Run nping in a while loop",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         print_timestamp = Attribute("printTimestamp",
             "Print timestamp before running nping",
             type = Types.Bool,
             default = False,
-            flags = Flags.ExecReadOnly)
+            flags = Flags.Design)
 
         cls._register_attribute(s)
         cls._register_attribute(p)
index a1f05e1..29089fd 100644 (file)
@@ -43,25 +43,25 @@ class UdpTunnel(LinuxApplication):
                 default = None,
                 allowed = ["PLAIN", "AES", "Blowfish", "DES", "DES3"],
                 type = Types.Enumerate, 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         cipher_key = Attribute("cipherKey",
                 "Specify a symmetric encryption key with which to protect "
                 "packets across the tunnel. python-crypto must be installed "
                 "on the system." ,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         txqueuelen = Attribute("txQueueLen",
                 "Specifies the interface's transmission queue length. "
                 "Defaults to 1000. ", 
                 type = Types.Integer, 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         bwlimit = Attribute("bwLimit",
                 "Specifies the interface's emulated bandwidth in bytes "
                 "per second.",
                 type = Types.Integer, 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         cls._register_attribute(cipher)
         cls._register_attribute(cipher_key)
@@ -198,7 +198,6 @@ class UdpTunnel(LinuxApplication):
             self.do_discover()
             self.do_provision()
  
-            self.debug("----- READY ---- ")
             self.set_ready()
 
     def do_start(self):
diff --git a/src/nepi/resources/ns3/classes/__init__.py b/src/nepi/resources/ns3/classes/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/nepi/resources/ns3/classes/aarf_wifi_manager.py b/src/nepi/resources/ns3/classes/aarf_wifi_manager.py
new file mode 100644 (file)
index 0000000..d737f3a
--- /dev/null
@@ -0,0 +1,177 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3AarfWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::AarfWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_successk = Attribute("SuccessK",
+            "Multiplication factor for the success threshold in the AARF algorithm.",
+            type = Types.Double,
+            default = "2",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_successk)
+
+        attr_timerk = Attribute("TimerK",
+            "Multiplication factor for the timer threshold in the AARF algorithm.",
+            type = Types.Double,
+            default = "2",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_timerk)
+
+        attr_maxsuccessthreshold = Attribute("MaxSuccessThreshold",
+            "Maximum value of the success threshold in the AARF algorithm.",
+            type = Types.Integer,
+            default = "60",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxsuccessthreshold)
+
+        attr_mintimerthreshold = Attribute("MinTimerThreshold",
+            "The minimum value for the \'timer\' threshold in the AARF algorithm.",
+            type = Types.Integer,
+            default = "15",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mintimerthreshold)
+
+        attr_minsuccessthreshold = Attribute("MinSuccessThreshold",
+            "The minimum value for the success threshold in the AARF algorithm.",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_minsuccessthreshold)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3AarfWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-aarf-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/aarfcd_wifi_manager.py b/src/nepi/resources/ns3/classes/aarfcd_wifi_manager.py
new file mode 100644 (file)
index 0000000..625662f
--- /dev/null
@@ -0,0 +1,217 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3AarfcdWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::AarfcdWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_successk = Attribute("SuccessK",
+            "Multiplication factor for the success threshold in the AARF algorithm.",
+            type = Types.Double,
+            default = "2",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_successk)
+
+        attr_timerk = Attribute("TimerK",
+            "Multiplication factor for the timer threshold in the AARF algorithm.",
+            type = Types.Double,
+            default = "2",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_timerk)
+
+        attr_maxsuccessthreshold = Attribute("MaxSuccessThreshold",
+            "Maximum value of the success threshold in the AARF algorithm.",
+            type = Types.Integer,
+            default = "60",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxsuccessthreshold)
+
+        attr_mintimerthreshold = Attribute("MinTimerThreshold",
+            "The minimum value for the \'timer\' threshold in the AARF algorithm.",
+            type = Types.Integer,
+            default = "15",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mintimerthreshold)
+
+        attr_minsuccessthreshold = Attribute("MinSuccessThreshold",
+            "The minimum value for the success threshold in the AARF algorithm.",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_minsuccessthreshold)
+
+        attr_minrtswnd = Attribute("MinRtsWnd",
+            "Minimum value for Rts window of Aarf-CD",
+            type = Types.Integer,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_minrtswnd)
+
+        attr_maxrtswnd = Attribute("MaxRtsWnd",
+            "Maximum value for Rts window of Aarf-CD",
+            type = Types.Integer,
+            default = "40",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxrtswnd)
+
+        attr_turnoffrtsafterratedecrease = Attribute("TurnOffRtsAfterRateDecrease",
+            "If true the RTS mechanism will be turned off when the rate will be decreased",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_turnoffrtsafterratedecrease)
+
+        attr_turnonrtsafterrateincrease = Attribute("TurnOnRtsAfterRateIncrease",
+            "If true the RTS mechanism will be turned on when the rate will be increased",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_turnonrtsafterrateincrease)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3AarfcdWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-aarfcd-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/adhoc_wifi_mac.py b/src/nepi/resources/ns3/classes/adhoc_wifi_mac.py
new file mode 100644 (file)
index 0000000..a53df07
--- /dev/null
@@ -0,0 +1,209 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
+
+@clsinit_copy
+class NS3AdhocWifiMac(NS3BaseWifiMac):
+    _rtype = "ns3::AdhocWifiMac"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_qossupported = Attribute("QosSupported",
+            "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_qossupported)
+
+        attr_htsupported = Attribute("HtSupported",
+            "This Boolean attribute is set to enable 802.11n support at this STA",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_htsupported)
+
+        attr_ctstoselfsupported = Attribute("CtsToSelfSupported",
+            "Use CTS to Self when using a rate that is not in the basic set rate",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ctstoselfsupported)
+
+        attr_ctstimeout = Attribute("CtsTimeout",
+            "When this timeout expires, the RTS/CTS handshake has failed.",
+            type = Types.String,
+            default = "+75000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ctstimeout)
+
+        attr_acktimeout = Attribute("AckTimeout",
+            "When this timeout expires, the DATA/ACK handshake has failed.",
+            type = Types.String,
+            default = "+75000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_acktimeout)
+
+        attr_basicblockacktimeout = Attribute("BasicBlockAckTimeout",
+            "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.",
+            type = Types.String,
+            default = "+281000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_basicblockacktimeout)
+
+        attr_compressedblockacktimeout = Attribute("CompressedBlockAckTimeout",
+            "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.",
+            type = Types.String,
+            default = "+107000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_compressedblockacktimeout)
+
+        attr_sifs = Attribute("Sifs",
+            "The value of the SIFS constant.",
+            type = Types.String,
+            default = "+16000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_sifs)
+
+        attr_eifsnodifs = Attribute("EifsNoDifs",
+            "The value of EIFS-DIFS",
+            type = Types.String,
+            default = "+60000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_eifsnodifs)
+
+        attr_slot = Attribute("Slot",
+            "The duration of a Slot.",
+            type = Types.String,
+            default = "+9000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_slot)
+
+        attr_pifs = Attribute("Pifs",
+            "The value of the PIFS constant.",
+            type = Types.String,
+            default = "+25000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pifs)
+
+        attr_rifs = Attribute("Rifs",
+            "The value of the RIFS constant.",
+            type = Types.String,
+            default = "+2000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rifs)
+
+        attr_maxpropagationdelay = Attribute("MaxPropagationDelay",
+            "The maximum propagation delay. Unused for now.",
+            type = Types.String,
+            default = "+3333.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpropagationdelay)
+
+        attr_ssid = Attribute("Ssid",
+            "The ssid we want to belong to.",
+            type = Types.String,
+            default = "default",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ssid)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        txokheader = Trace("TxOkHeader", "The header of successfully transmitted packet")
+
+        cls._register_trace(txokheader)
+
+        txerrheader = Trace("TxErrHeader", "The header of unsuccessfully transmitted packet")
+
+        cls._register_trace(txerrheader)
+
+        mactx = Trace("MacTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.")
+
+        cls._register_trace(mactx)
+
+        mactxdrop = Trace("MacTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.")
+
+        cls._register_trace(mactxdrop)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+        macrxdrop = Trace("MacRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.")
+
+        cls._register_trace(macrxdrop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3AdhocWifiMac, self).__init__(ec, guid)
+        self._home = "ns3-adhoc-wifi-mac-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/aloha_noack_net_device.py b/src/nepi/resources/ns3/classes/aloha_noack_net_device.py
new file mode 100644 (file)
index 0000000..b45b431
--- /dev/null
@@ -0,0 +1,77 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3AlohaNoackNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::AlohaNoackNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_address = Attribute("Address",
+            "The MAC address of this device.",
+            type = Types.String,
+            default = "12:34:56:78:90:12",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_address)
+
+        attr_mtu = Attribute("Mtu",
+            "The Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "1500",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device")
+
+        cls._register_trace(mactx)
+
+        mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission")
+
+        cls._register_trace(mactxdrop)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3AlohaNoackNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-aloha-noack-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/amrr_wifi_manager.py b/src/nepi/resources/ns3/classes/amrr_wifi_manager.py
new file mode 100644 (file)
index 0000000..dfb13f4
--- /dev/null
@@ -0,0 +1,177 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3AmrrWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::AmrrWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_updateperiod = Attribute("UpdatePeriod",
+            "The interval between decisions about rate control changes",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_updateperiod)
+
+        attr_failureratio = Attribute("FailureRatio",
+            "Ratio of minimum erroneous transmissions needed to switch to a lower rate",
+            type = Types.Double,
+            default = "0.333333",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_failureratio)
+
+        attr_successratio = Attribute("SuccessRatio",
+            "Ratio of maximum erroneous transmissions needed to switch to a higher rate",
+            type = Types.Double,
+            default = "0.1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_successratio)
+
+        attr_maxsuccessthreshold = Attribute("MaxSuccessThreshold",
+            "Maximum number of consecutive success periods needed to switch to a higher rate",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxsuccessthreshold)
+
+        attr_minsuccessthreshold = Attribute("MinSuccessThreshold",
+            "Minimum number of consecutive success periods needed to switch to a higher rate",
+            type = Types.Integer,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_minsuccessthreshold)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3AmrrWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-amrr-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/ap_wifi_mac.py b/src/nepi/resources/ns3/classes/ap_wifi_mac.py
new file mode 100644 (file)
index 0000000..8802aa7
--- /dev/null
@@ -0,0 +1,249 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
+
+@clsinit_copy
+class NS3ApWifiMac(NS3BaseWifiMac):
+    _rtype = "ns3::ApWifiMac"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_beaconinterval = Attribute("BeaconInterval",
+            "Delay between two beacons",
+            type = Types.String,
+            default = "+102400000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_beaconinterval)
+
+        attr_beaconjitter = Attribute("BeaconJitter",
+            "A uniform random variable to cause the initial beacon starting time (after simulation time 0) to be distributed between 0 and the BeaconInterval.",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_beaconjitter)
+
+        attr_enablebeaconjitter = Attribute("EnableBeaconJitter",
+            "If beacons are enabled, whether to jitter the initial send event.",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_enablebeaconjitter)
+
+        attr_beacongeneration = Attribute("BeaconGeneration",
+            "Whether or not beacons are generated.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_beacongeneration)
+
+        attr_qossupported = Attribute("QosSupported",
+            "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_qossupported)
+
+        attr_htsupported = Attribute("HtSupported",
+            "This Boolean attribute is set to enable 802.11n support at this STA",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_htsupported)
+
+        attr_ctstoselfsupported = Attribute("CtsToSelfSupported",
+            "Use CTS to Self when using a rate that is not in the basic set rate",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ctstoselfsupported)
+
+        attr_ctstimeout = Attribute("CtsTimeout",
+            "When this timeout expires, the RTS/CTS handshake has failed.",
+            type = Types.String,
+            default = "+75000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ctstimeout)
+
+        attr_acktimeout = Attribute("AckTimeout",
+            "When this timeout expires, the DATA/ACK handshake has failed.",
+            type = Types.String,
+            default = "+75000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_acktimeout)
+
+        attr_basicblockacktimeout = Attribute("BasicBlockAckTimeout",
+            "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.",
+            type = Types.String,
+            default = "+281000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_basicblockacktimeout)
+
+        attr_compressedblockacktimeout = Attribute("CompressedBlockAckTimeout",
+            "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.",
+            type = Types.String,
+            default = "+107000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_compressedblockacktimeout)
+
+        attr_sifs = Attribute("Sifs",
+            "The value of the SIFS constant.",
+            type = Types.String,
+            default = "+16000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_sifs)
+
+        attr_eifsnodifs = Attribute("EifsNoDifs",
+            "The value of EIFS-DIFS",
+            type = Types.String,
+            default = "+60000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_eifsnodifs)
+
+        attr_slot = Attribute("Slot",
+            "The duration of a Slot.",
+            type = Types.String,
+            default = "+9000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_slot)
+
+        attr_pifs = Attribute("Pifs",
+            "The value of the PIFS constant.",
+            type = Types.String,
+            default = "+25000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pifs)
+
+        attr_rifs = Attribute("Rifs",
+            "The value of the RIFS constant.",
+            type = Types.String,
+            default = "+2000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rifs)
+
+        attr_maxpropagationdelay = Attribute("MaxPropagationDelay",
+            "The maximum propagation delay. Unused for now.",
+            type = Types.String,
+            default = "+3333.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpropagationdelay)
+
+        attr_ssid = Attribute("Ssid",
+            "The ssid we want to belong to.",
+            type = Types.String,
+            default = "default",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ssid)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        txokheader = Trace("TxOkHeader", "The header of successfully transmitted packet")
+
+        cls._register_trace(txokheader)
+
+        txerrheader = Trace("TxErrHeader", "The header of unsuccessfully transmitted packet")
+
+        cls._register_trace(txerrheader)
+
+        mactx = Trace("MacTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.")
+
+        cls._register_trace(mactx)
+
+        mactxdrop = Trace("MacTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.")
+
+        cls._register_trace(mactxdrop)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+        macrxdrop = Trace("MacRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.")
+
+        cls._register_trace(macrxdrop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3ApWifiMac, self).__init__(ec, guid)
+        self._home = "ns3-ap-wifi-mac-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/arf_wifi_manager.py b/src/nepi/resources/ns3/classes/arf_wifi_manager.py
new file mode 100644 (file)
index 0000000..9714846
--- /dev/null
@@ -0,0 +1,147 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3ArfWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::ArfWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_timerthreshold = Attribute("TimerThreshold",
+            "The \'timer\' threshold in the ARF algorithm.",
+            type = Types.Integer,
+            default = "15",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_timerthreshold)
+
+        attr_successthreshold = Attribute("SuccessThreshold",
+            "The minimum number of sucessfull transmissions to try a new rate.",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_successthreshold)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3ArfWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-arf-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/arp_l3protocol.py b/src/nepi/resources/ns3/classes/arp_l3protocol.py
new file mode 100644 (file)
index 0000000..d027d52
--- /dev/null
@@ -0,0 +1,55 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3arpl3protocol import NS3BaseArpL3Protocol 
+
+@clsinit_copy
+class NS3ArpL3Protocol(NS3BaseArpL3Protocol):
+    _rtype = "ns3::ArpL3Protocol"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_requestjitter = Attribute("RequestJitter",
+            "The jitter in ms a node is allowed to wait before sending an ARP request. Some jitter aims to prevent collisions. By default, the model will wait for a duration in ms defined by a uniform random-variable between 0 and RequestJitter",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=0.0|Max=10.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_requestjitter)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        drop = Trace("Drop", "Packet dropped because not enough room in pending queue for a specific cache entry.")
+
+        cls._register_trace(drop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3ArpL3Protocol, self).__init__(ec, guid)
+        self._home = "ns3-arp-l3protocol-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/base_station_net_device.py b/src/nepi/resources/ns3/classes/base_station_net_device.py
new file mode 100644 (file)
index 0000000..c0130be
--- /dev/null
@@ -0,0 +1,169 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3BaseStationNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::BaseStationNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_initialranginterval = Attribute("InitialRangInterval",
+            "Time between Initial Ranging regions assigned by the BS. Maximum is 2s",
+            type = Types.String,
+            default = "+50000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_initialranginterval)
+
+        attr_dcdinterval = Attribute("DcdInterval",
+            "Time between transmission of DCD messages. Maximum value is 10s.",
+            type = Types.String,
+            default = "+3000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_dcdinterval)
+
+        attr_ucdinterval = Attribute("UcdInterval",
+            "Time between transmission of UCD messages. Maximum value is 10s.",
+            type = Types.String,
+            default = "+3000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ucdinterval)
+
+        attr_intervalt8 = Attribute("IntervalT8",
+            "Wait for DSA/DSC Acknowledge timeout. Maximum 300ms.",
+            type = Types.String,
+            default = "+50000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_intervalt8)
+
+        attr_rangreqoppsize = Attribute("RangReqOppSize",
+            "The ranging opportunity size in symbols",
+            type = Types.Integer,
+            default = "8",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rangreqoppsize)
+
+        attr_bwreqoppsize = Attribute("BwReqOppSize",
+            "The bandwidth request opportunity size in symbols",
+            type = Types.Integer,
+            default = "2",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_bwreqoppsize)
+
+        attr_maxrangcorrectionretries = Attribute("MaxRangCorrectionRetries",
+            "Number of retries on contention Ranging Requests",
+            type = Types.Integer,
+            default = "16",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxrangcorrectionretries)
+
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "1400",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+        attr_rtg = Attribute("RTG",
+            "receive/transmit transition gap.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtg)
+
+        attr_ttg = Attribute("TTG",
+            "transmit/receive transition gap.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ttg)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        bstx = Trace("BSTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.")
+
+        cls._register_trace(bstx)
+
+        bstxdrop = Trace("BSTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.")
+
+        cls._register_trace(bstxdrop)
+
+        bspromiscrx = Trace("BSPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(bspromiscrx)
+
+        bsrx = Trace("BSRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(bsrx)
+
+        bsrxdrop = Trace("BSRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.")
+
+        cls._register_trace(bsrxdrop)
+
+        rx = Trace("Rx", "Receive trace")
+
+        cls._register_trace(rx)
+
+        tx = Trace("Tx", "Transmit trace")
+
+        cls._register_trace(tx)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3BaseStationNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-base-station-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/bridge_channel.py b/src/nepi/resources/ns3/classes/bridge_channel.py
new file mode 100644 (file)
index 0000000..4075f54
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3BridgeChannel(NS3BaseChannel):
+    _rtype = "ns3::BridgeChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3BridgeChannel, self).__init__(ec, guid)
+        self._home = "ns3-bridge-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/bridge_net_device.py b/src/nepi/resources/ns3/classes/bridge_net_device.py
new file mode 100644 (file)
index 0000000..d1313c4
--- /dev/null
@@ -0,0 +1,70 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3BridgeNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::BridgeNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "1500",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+        attr_enablelearning = Attribute("EnableLearning",
+            "Enable the learning mode of the Learning Bridge",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_enablelearning)
+
+        attr_expirationtime = Attribute("ExpirationTime",
+            "Time it takes for learned MAC state entry to expire.",
+            type = Types.String,
+            default = "+300000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_expirationtime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3BridgeNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-bridge-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/bulk_send_application.py b/src/nepi/resources/ns3/classes/bulk_send_application.py
new file mode 100644 (file)
index 0000000..f7db2e9
--- /dev/null
@@ -0,0 +1,105 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3BulkSendApplication(NS3BaseApplication):
+    _rtype = "ns3::BulkSendApplication"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_sendsize = Attribute("SendSize",
+            "The amount of data to send each time.",
+            type = Types.Integer,
+            default = "512",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_sendsize)
+
+        attr_remote = Attribute("Remote",
+            "The address of the destination",
+            type = Types.String,
+            default = "00-00-00",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remote)
+
+        attr_maxbytes = Attribute("MaxBytes",
+            "The total number of bytes to send. Once these bytes are sent, no data  is sent again. The value zero means that there is no limit.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxbytes)
+
+        attr_protocol = Attribute("Protocol",
+            "The type of protocol to use.",
+            type = Types.String,
+            default = "ns3::TcpSocketFactory",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_protocol)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        tx = Trace("Tx", "A new packet is created and is sent")
+
+        cls._register_trace(tx)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3BulkSendApplication, self).__init__(ec, guid)
+        self._home = "ns3-bulk-send-application-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/burst_error_model.py b/src/nepi/resources/ns3/classes/burst_error_model.py
new file mode 100644 (file)
index 0000000..bac2cb0
--- /dev/null
@@ -0,0 +1,80 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+class NS3BurstErrorModel(NS3BaseErrorModel):
+    _rtype = "ns3::BurstErrorModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_errorrate = Attribute("ErrorRate",
+            "The burst error event.",
+            type = Types.Double,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_errorrate)
+
+        attr_burststart = Attribute("BurstStart",
+            "The decision variable attached to this error model.",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=0.0|Max=1.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_burststart)
+
+        attr_burstsize = Attribute("BurstSize",
+            "The number of packets being corrupted at one drop.",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=1|Max=4]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_burstsize)
+
+        attr_isenabled = Attribute("IsEnabled",
+            "Whether this ErrorModel is enabled or not.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_isenabled)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3BurstErrorModel, self).__init__(ec, guid)
+        self._home = "ns3-burst-error-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/cara_wifi_manager.py b/src/nepi/resources/ns3/classes/cara_wifi_manager.py
new file mode 100644 (file)
index 0000000..8f336f1
--- /dev/null
@@ -0,0 +1,167 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3CaraWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::CaraWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_probethreshold = Attribute("ProbeThreshold",
+            "The number of consecutive transmissions failure to activate the RTS probe.",
+            type = Types.Integer,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_probethreshold)
+
+        attr_failurethreshold = Attribute("FailureThreshold",
+            "The number of consecutive transmissions failure to decrease the rate.",
+            type = Types.Integer,
+            default = "2",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_failurethreshold)
+
+        attr_successthreshold = Attribute("SuccessThreshold",
+            "The minimum number of sucessfull transmissions to try a new rate.",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_successthreshold)
+
+        attr_timeout = Attribute("Timeout",
+            "The \'timer\' in the CARA algorithm",
+            type = Types.Integer,
+            default = "15",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_timeout)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3CaraWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-cara-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/constant_acceleration_mobility_model.py b/src/nepi/resources/ns3/classes/constant_acceleration_mobility_model.py
new file mode 100644 (file)
index 0000000..662f9e7
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3ConstantAccelerationMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::ConstantAccelerationMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3ConstantAccelerationMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-constant-acceleration-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/constant_position_mobility_model.py b/src/nepi/resources/ns3/classes/constant_position_mobility_model.py
new file mode 100644 (file)
index 0000000..03ec389
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3ConstantPositionMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::ConstantPositionMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3ConstantPositionMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-constant-position-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/constant_rate_wifi_manager.py b/src/nepi/resources/ns3/classes/constant_rate_wifi_manager.py
new file mode 100644 (file)
index 0000000..decba32
--- /dev/null
@@ -0,0 +1,147 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3ConstantRateWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::ConstantRateWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_datamode = Attribute("DataMode",
+            "The transmission mode to use for every data packet transmission",
+            type = Types.String,
+            default = "OfdmRate6Mbps",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_datamode)
+
+        attr_controlmode = Attribute("ControlMode",
+            "The transmission mode to use for every control packet transmission.",
+            type = Types.String,
+            default = "OfdmRate6Mbps",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_controlmode)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3ConstantRateWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-constant-rate-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.py b/src/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.py
new file mode 100644 (file)
index 0000000..9722bd4
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationdelaymodel import NS3BasePropagationDelayModel 
+
+@clsinit_copy
+class NS3ConstantSpeedPropagationDelayModel(NS3BasePropagationDelayModel):
+    _rtype = "ns3::ConstantSpeedPropagationDelayModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_speed = Attribute("Speed",
+            "The speed (m/s)",
+            type = Types.Double,
+            default = "3e+08",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_speed)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3ConstantSpeedPropagationDelayModel, self).__init__(ec, guid)
+        self._home = "ns3-constant-speed-propagation-delay-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/constant_velocity_mobility_model.py b/src/nepi/resources/ns3/classes/constant_velocity_mobility_model.py
new file mode 100644 (file)
index 0000000..e0dfd0f
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3ConstantVelocityMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::ConstantVelocityMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3ConstantVelocityMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-constant-velocity-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/cost231propagation_loss_model.py b/src/nepi/resources/ns3/classes/cost231propagation_loss_model.py
new file mode 100644 (file)
index 0000000..2bbbe3d
--- /dev/null
@@ -0,0 +1,90 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3Cost231PropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::Cost231PropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_lambda = Attribute("Lambda",
+            "The wavelength  (default is 2.3 GHz at 300 000 km/s).",
+            type = Types.Double,
+            default = "0.130435",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_lambda)
+
+        attr_frequency = Attribute("Frequency",
+            "The Frequency  (default is 2.3 GHz).",
+            type = Types.Double,
+            default = "2.3e+09",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_frequency)
+
+        attr_bsantennaheight = Attribute("BSAntennaHeight",
+            " BS Antenna Height (default is 50m).",
+            type = Types.Double,
+            default = "50",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_bsantennaheight)
+
+        attr_ssantennaheight = Attribute("SSAntennaHeight",
+            " SS Antenna Height (default is 3m).",
+            type = Types.Double,
+            default = "3",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ssantennaheight)
+
+        attr_mindistance = Attribute("MinDistance",
+            "The distance under which the propagation model refuses to give results (m) ",
+            type = Types.Double,
+            default = "0.5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mindistance)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3Cost231PropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-cost231propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/csma_channel.py b/src/nepi/resources/ns3/classes/csma_channel.py
new file mode 100644 (file)
index 0000000..d839f32
--- /dev/null
@@ -0,0 +1,70 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3CsmaChannel(NS3BaseChannel):
+    _rtype = "ns3::CsmaChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_datarate = Attribute("DataRate",
+            "The transmission data rate to be provided to devices connected to the channel",
+            type = Types.String,
+            default = "4294967295bps",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_datarate)
+
+        attr_delay = Attribute("Delay",
+            "Transmission delay through the channel",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_delay)
+
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3CsmaChannel, self).__init__(ec, guid)
+        self._home = "ns3-csma-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/csma_net_device.py b/src/nepi/resources/ns3/classes/csma_net_device.py
new file mode 100644 (file)
index 0000000..b368b27
--- /dev/null
@@ -0,0 +1,129 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3CsmaNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::CsmaNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_address = Attribute("Address",
+            "The MAC address of this device.",
+            type = Types.String,
+            default = "ff:ff:ff:ff:ff:ff",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_address)
+
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "1500",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+        attr_sendenable = Attribute("SendEnable",
+            "Enable or disable the transmitter section of the device.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_sendenable)
+
+        attr_receiveenable = Attribute("ReceiveEnable",
+            "Enable or disable the receiver section of the device.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_receiveenable)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device")
+
+        cls._register_trace(mactx)
+
+        mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission")
+
+        cls._register_trace(mactxdrop)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+        mactxbackoff = Trace("MacTxBackoff", "Trace source indicating a packet has been delayed by the CSMA backoff process")
+
+        cls._register_trace(mactxbackoff)
+
+        phytxbegin = Trace("PhyTxBegin", "Trace source indicating a packet has begun transmitting over the channel")
+
+        cls._register_trace(phytxbegin)
+
+        phytxend = Trace("PhyTxEnd", "Trace source indicating a packet has been completely transmitted over the channel")
+
+        cls._register_trace(phytxend)
+
+        phytxdrop = Trace("PhyTxDrop", "Trace source indicating a packet has been dropped by the device during transmission")
+
+        cls._register_trace(phytxdrop)
+
+        phyrxend = Trace("PhyRxEnd", "Trace source indicating a packet has been completely received by the device")
+
+        cls._register_trace(phyrxend)
+
+        phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception")
+
+        cls._register_trace(phyrxdrop)
+
+        sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(sniffer)
+
+        promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(promiscsniffer)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3CsmaNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-csma-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/dce_application.py b/src/nepi/resources/ns3/classes/dce_application.py
new file mode 100644 (file)
index 0000000..9b42c54
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication 
+
+@clsinit_copy
+class NS3DceApplication(NS3BaseDceApplication):
+    _rtype = "ns3::DceApplication"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        processstarted = Trace("ProcessStarted", "notify when the dce is started")
+
+        cls._register_trace(processstarted)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3DceApplication, self).__init__(ec, guid)
+        self._home = "ns3-dce-application-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/drop_tail_queue.py b/src/nepi/resources/ns3/classes/drop_tail_queue.py
new file mode 100644 (file)
index 0000000..550d925
--- /dev/null
@@ -0,0 +1,73 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3queue import NS3BaseQueue 
+
+@clsinit_copy
+class NS3DropTailQueue(NS3BaseQueue):
+    _rtype = "ns3::DropTailQueue"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_maxpackets = Attribute("MaxPackets",
+            "The maximum number of packets accepted by this DropTailQueue.",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpackets)
+
+        attr_maxbytes = Attribute("MaxBytes",
+            "The maximum number of bytes accepted by this DropTailQueue.",
+            type = Types.Integer,
+            default = "6553500",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxbytes)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        enqueue = Trace("Enqueue", "Enqueue a packet in the queue.")
+
+        cls._register_trace(enqueue)
+
+        dequeue = Trace("Dequeue", "Dequeue a packet from the queue.")
+
+        cls._register_trace(dequeue)
+
+        drop = Trace("Drop", "Drop a packet stored in the queue.")
+
+        cls._register_trace(drop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3DropTailQueue, self).__init__(ec, guid)
+        self._home = "ns3-drop-tail-queue-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/dsrdsr_routing.py b/src/nepi/resources/ns3/classes/dsrdsr_routing.py
new file mode 100644 (file)
index 0000000..e6f83ff
--- /dev/null
@@ -0,0 +1,449 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3dsrDsrRouting(NS3Base):
+    _rtype = "ns3::dsr::DsrRouting"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_maxsendbufflen = Attribute("MaxSendBuffLen",
+            "Maximum number of packets that can be stored in send buffer.",
+            type = Types.Integer,
+            default = "64",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxsendbufflen)
+
+        attr_maxsendbufftime = Attribute("MaxSendBuffTime",
+            "Maximum time packets can be queued in the send buffer .",
+            type = Types.String,
+            default = "+30000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxsendbufftime)
+
+        attr_maxmaintlen = Attribute("MaxMaintLen",
+            "Maximum number of packets that can be stored in maintenance buffer.",
+            type = Types.Integer,
+            default = "50",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxmaintlen)
+
+        attr_maxmainttime = Attribute("MaxMaintTime",
+            "Maximum time packets can be queued in maintenance buffer.",
+            type = Types.String,
+            default = "+30000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxmainttime)
+
+        attr_maxcachelen = Attribute("MaxCacheLen",
+            "Maximum number of route entries that can be stored in route cache.",
+            type = Types.Integer,
+            default = "64",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxcachelen)
+
+        attr_routecachetimeout = Attribute("RouteCacheTimeout",
+            "Maximum time the route cache can be queued in route cache.",
+            type = Types.String,
+            default = "+300000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_routecachetimeout)
+
+        attr_maxentrieseachdst = Attribute("MaxEntriesEachDst",
+            "Maximum number of route entries for a single destination to respond.",
+            type = Types.Integer,
+            default = "20",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxentrieseachdst)
+
+        attr_sendbuffinterval = Attribute("SendBuffInterval",
+            "How often to check send buffer for packet with route.",
+            type = Types.String,
+            default = "+500000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_sendbuffinterval)
+
+        attr_nodetraversaltime = Attribute("NodeTraversalTime",
+            "The time it takes to traverse two neighboring nodes.",
+            type = Types.String,
+            default = "+40000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nodetraversaltime)
+
+        attr_rreqretries = Attribute("RreqRetries",
+            "Maximum number of retransmissions for request discovery of a route.",
+            type = Types.Integer,
+            default = "16",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rreqretries)
+
+        attr_maintenanceretries = Attribute("MaintenanceRetries",
+            "Maximum number of retransmissions for data packets from maintenance buffer.",
+            type = Types.Integer,
+            default = "2",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maintenanceretries)
+
+        attr_requesttablesize = Attribute("RequestTableSize",
+            "Maximum number of request entries in the request table, set this as the number of nodes in the simulation.",
+            type = Types.Integer,
+            default = "64",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_requesttablesize)
+
+        attr_requestidsize = Attribute("RequestIdSize",
+            "Maximum number of request source Ids in the request table.",
+            type = Types.Integer,
+            default = "16",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_requestidsize)
+
+        attr_uniquerequestidsize = Attribute("UniqueRequestIdSize",
+            "Maximum number of request Ids in the request table for a single destination.",
+            type = Types.Integer,
+            default = "256",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_uniquerequestidsize)
+
+        attr_nonproprequesttimeout = Attribute("NonPropRequestTimeout",
+            "The timeout value for non-propagation request.",
+            type = Types.String,
+            default = "+30000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonproprequesttimeout)
+
+        attr_discoveryhoplimit = Attribute("DiscoveryHopLimit",
+            "The max discovery hop limit for route requests.",
+            type = Types.Integer,
+            default = "255",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_discoveryhoplimit)
+
+        attr_maxsalvagecount = Attribute("MaxSalvageCount",
+            "The max salvage count for a single data packet.",
+            type = Types.Integer,
+            default = "15",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxsalvagecount)
+
+        attr_blacklisttimeout = Attribute("BlacklistTimeout",
+            "The time for a neighbor to stay in blacklist.",
+            type = Types.String,
+            default = "+3000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_blacklisttimeout)
+
+        attr_gratreplyholdoff = Attribute("GratReplyHoldoff",
+            "The time for gratuitous reply entry to expire.",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_gratreplyholdoff)
+
+        attr_broadcastjitter = Attribute("BroadcastJitter",
+            "The jitter time to avoid collision for broadcast packets.",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_broadcastjitter)
+
+        attr_linkacktimeout = Attribute("LinkAckTimeout",
+            "The time a packet in maintenance buffer wait for link acknowledgment.",
+            type = Types.String,
+            default = "+100000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_linkacktimeout)
+
+        attr_trylinkacks = Attribute("TryLinkAcks",
+            "The number of link acknowledgment to use.",
+            type = Types.Integer,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_trylinkacks)
+
+        attr_passiveacktimeout = Attribute("PassiveAckTimeout",
+            "The time a packet in maintenance buffer wait for passive acknowledgment.",
+            type = Types.String,
+            default = "+100000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_passiveacktimeout)
+
+        attr_trypassiveacks = Attribute("TryPassiveAcks",
+            "The number of passive acknowledgment to use.",
+            type = Types.Integer,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_trypassiveacks)
+
+        attr_requestperiod = Attribute("RequestPeriod",
+            "The base time interval between route requests.",
+            type = Types.String,
+            default = "+500000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_requestperiod)
+
+        attr_maxrequestperiod = Attribute("MaxRequestPeriod",
+            "The max time interval between route requests.",
+            type = Types.String,
+            default = "+10000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxrequestperiod)
+
+        attr_grareplytablesize = Attribute("GraReplyTableSize",
+            "The gratuitous reply table size.",
+            type = Types.Integer,
+            default = "64",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_grareplytablesize)
+
+        attr_cachetype = Attribute("CacheType",
+            "Use Link Cache or use Path Cache",
+            type = Types.String,
+            default = "LinkCache",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_cachetype)
+
+        attr_stabilitydecrfactor = Attribute("StabilityDecrFactor",
+            "The stability decrease factor for link cache",
+            type = Types.Integer,
+            default = "2",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stabilitydecrfactor)
+
+        attr_stabilityincrfactor = Attribute("StabilityIncrFactor",
+            "The stability increase factor for link cache",
+            type = Types.Integer,
+            default = "4",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stabilityincrfactor)
+
+        attr_initstability = Attribute("InitStability",
+            "The initial stability factor for link cache",
+            type = Types.String,
+            default = "+25000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_initstability)
+
+        attr_minlifetime = Attribute("MinLifeTime",
+            "The minimal life time for link cache",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_minlifetime)
+
+        attr_useextends = Attribute("UseExtends",
+            "The extension time for link cache",
+            type = Types.String,
+            default = "+120000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_useextends)
+
+        attr_enablesubroute = Attribute("EnableSubRoute",
+            "Enables saving of sub route when receiving route error messages, only available when using path route cache",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_enablesubroute)
+
+        attr_retransincr = Attribute("RetransIncr",
+            "The increase time for retransmission timer when facing network congestion",
+            type = Types.String,
+            default = "+20000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_retransincr)
+
+        attr_maxnetworkqueuesize = Attribute("MaxNetworkQueueSize",
+            "The max number of packet to save in the network queue.",
+            type = Types.Integer,
+            default = "400",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxnetworkqueuesize)
+
+        attr_maxnetworkqueuedelay = Attribute("MaxNetworkQueueDelay",
+            "The max time for a packet to stay in the network queue.",
+            type = Types.String,
+            default = "+30000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxnetworkqueuedelay)
+
+        attr_numpriorityqueues = Attribute("NumPriorityQueues",
+            "The max number of packet to save in the network queue.",
+            type = Types.Integer,
+            default = "2",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_numpriorityqueues)
+
+        attr_linkacknowledgment = Attribute("LinkAcknowledgment",
+            "Enable Link layer acknowledgment mechanism",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_linkacknowledgment)
+
+        attr_protocolnumber = Attribute("ProtocolNumber",
+            "The Ip protocol number.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_protocolnumber)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        tx = Trace("Tx", "Send DSR packet.")
+
+        cls._register_trace(tx)
+
+        drop = Trace("Drop", "Drop DSR packet")
+
+        cls._register_trace(drop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3dsrDsrRouting, self).__init__(ec, guid)
+        self._home = "ns3-dsr-dsr-routing-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/emu_net_device.py b/src/nepi/resources/ns3/classes/emu_net_device.py
new file mode 100644 (file)
index 0000000..09a81c5
--- /dev/null
@@ -0,0 +1,125 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3EmuNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::EmuNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+        attr_address = Attribute("Address",
+            "The ns-3 MAC address of this (virtual) device.",
+            type = Types.String,
+            default = "ff:ff:ff:ff:ff:ff",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_address)
+
+        attr_devicename = Attribute("DeviceName",
+            "The name of the underlying real device (e.g. eth1).",
+            type = Types.String,
+            default = "eth1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_devicename)
+
+        attr_start = Attribute("Start",
+            "The simulation time at which to spin up the device thread.",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_start)
+
+        attr_stop = Attribute("Stop",
+            "The simulation time at which to tear down the device thread.",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stop)
+
+        attr_rxqueuesize = Attribute("RxQueueSize",
+            "Maximum size of the read queue.  This value limits number of packets that have been read from the network into a memory buffer but have not yet been processed by the simulator.",
+            type = Types.Integer,
+            default = "1000",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rxqueuesize)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device")
+
+        cls._register_trace(mactx)
+
+        mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission")
+
+        cls._register_trace(mactxdrop)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+        sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(sniffer)
+
+        promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(promiscsniffer)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3EmuNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-emu-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/error_channel.py b/src/nepi/resources/ns3/classes/error_channel.py
new file mode 100644 (file)
index 0000000..1a9e2ad
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3ErrorChannel(NS3BaseChannel):
+    _rtype = "ns3::ErrorChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3ErrorChannel, self).__init__(ec, guid)
+        self._home = "ns3-error-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/error_net_device.py b/src/nepi/resources/ns3/classes/error_net_device.py
new file mode 100644 (file)
index 0000000..7b59ba8
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3ErrorNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::ErrorNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        pass
+
+    @classmethod
+    def _register_traces(cls):
+        
+        phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception")
+
+        cls._register_trace(phyrxdrop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3ErrorNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-error-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/fd_net_device.py b/src/nepi/resources/ns3/classes/fd_net_device.py
new file mode 100644 (file)
index 0000000..62fc602
--- /dev/null
@@ -0,0 +1,115 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3FdNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::FdNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_address = Attribute("Address",
+            "The MAC address of this device.",
+            type = Types.String,
+            default = "ff:ff:ff:ff:ff:ff",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_address)
+
+        attr_start = Attribute("Start",
+            "The simulation time at which to spin up the device thread.",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_start)
+
+        attr_stop = Attribute("Stop",
+            "The simulation time at which to tear down the device thread.",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stop)
+
+        attr_encapsulationmode = Attribute("EncapsulationMode",
+            "The link-layer encapsulation type to use.",
+            type = Types.Enumerate,
+            default = "Dix",  
+            allowed = ["Dix","Llc","DixPi"],
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_encapsulationmode)
+
+        attr_rxqueuesize = Attribute("RxQueueSize",
+            "Maximum size of the read queue.  This value limits number of packets that have been read from the network into a memory buffer but have not yet been processed by the simulator.",
+            type = Types.Integer,
+            default = "1000",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rxqueuesize)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device")
+
+        cls._register_trace(mactx)
+
+        mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission")
+
+        cls._register_trace(mactxdrop)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+        sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(sniffer)
+
+        promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(promiscsniffer)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3FdNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-fd-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/fixed_rss_loss_model.py b/src/nepi/resources/ns3/classes/fixed_rss_loss_model.py
new file mode 100644 (file)
index 0000000..518b4c5
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3FixedRssLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::FixedRssLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_rss = Attribute("Rss",
+            "The fixed receiver Rss.",
+            type = Types.Double,
+            default = "-150",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rss)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3FixedRssLossModel, self).__init__(ec, guid)
+        self._home = "ns3-fixed-rss-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/friis_propagation_loss_model.py b/src/nepi/resources/ns3/classes/friis_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..54d2d4f
--- /dev/null
@@ -0,0 +1,70 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3FriisPropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::FriisPropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_frequency = Attribute("Frequency",
+            "The carrier frequency (in Hz) at which propagation occurs  (default is 5.15 GHz).",
+            type = Types.Double,
+            default = "5.15e+09",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_frequency)
+
+        attr_systemloss = Attribute("SystemLoss",
+            "The system loss",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_systemloss)
+
+        attr_mindistance = Attribute("MinDistance",
+            "The distance under which the propagation model refuses to give results (m)",
+            type = Types.Double,
+            default = "0.5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mindistance)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3FriisPropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-friis-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/gauss_markov_mobility_model.py b/src/nepi/resources/ns3/classes/gauss_markov_mobility_model.py
new file mode 100644 (file)
index 0000000..1d380a7
--- /dev/null
@@ -0,0 +1,155 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3GaussMarkovMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::GaussMarkovMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_bounds = Attribute("Bounds",
+            "Bounds of the area to cruise.",
+            type = Types.String,
+            default = "-100|100|-100|100|0|100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_bounds)
+
+        attr_timestep = Attribute("TimeStep",
+            "Change current direction and speed after moving for this time.",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_timestep)
+
+        attr_alpha = Attribute("Alpha",
+            "A constant representing the tunable parameter in the Gauss-Markov model.",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_alpha)
+
+        attr_meanvelocity = Attribute("MeanVelocity",
+            "A random variable used to assign the average velocity.",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=0.0|Max=1.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_meanvelocity)
+
+        attr_meandirection = Attribute("MeanDirection",
+            "A random variable used to assign the average direction.",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=0.0|Max=6.283185307]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_meandirection)
+
+        attr_meanpitch = Attribute("MeanPitch",
+            "A random variable used to assign the average pitch.",
+            type = Types.String,
+            default = "ns3::ConstantRandomVariable[Constant=0.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_meanpitch)
+
+        attr_normalvelocity = Attribute("NormalVelocity",
+            "A gaussian random variable used to calculate the next velocity value.",
+            type = Types.String,
+            default = "ns3::NormalRandomVariable[Mean=0.0|Variance=1.0|Bound=10.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_normalvelocity)
+
+        attr_normaldirection = Attribute("NormalDirection",
+            "A gaussian random variable used to calculate the next direction value.",
+            type = Types.String,
+            default = "ns3::NormalRandomVariable[Mean=0.0|Variance=1.0|Bound=10.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_normaldirection)
+
+        attr_normalpitch = Attribute("NormalPitch",
+            "A gaussian random variable used to calculate the next pitch value.",
+            type = Types.String,
+            default = "ns3::NormalRandomVariable[Mean=0.0|Variance=1.0|Bound=10.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_normalpitch)
+
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3GaussMarkovMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-gauss-markov-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/hierarchical_mobility_model.py b/src/nepi/resources/ns3/classes/hierarchical_mobility_model.py
new file mode 100644 (file)
index 0000000..97ce062
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3HierarchicalMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::HierarchicalMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3HierarchicalMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-hierarchical-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.py b/src/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..26c12a9
--- /dev/null
@@ -0,0 +1,90 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3HybridBuildingsPropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::HybridBuildingsPropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_los2nlosthr = Attribute("Los2NlosThr",
+            " Threshold from LoS to NLoS in ITU 1411 [m].",
+            type = Types.Double,
+            default = "200",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_los2nlosthr)
+
+        attr_shadowsigmaoutdoor = Attribute("ShadowSigmaOutdoor",
+            "Standard deviation of the normal distribution used for calculate the shadowing for outdoor nodes",
+            type = Types.Double,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_shadowsigmaoutdoor)
+
+        attr_shadowsigmaindoor = Attribute("ShadowSigmaIndoor",
+            "Standard deviation of the normal distribution used for calculate the shadowing for indoor nodes ",
+            type = Types.Double,
+            default = "8",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_shadowsigmaindoor)
+
+        attr_shadowsigmaextwalls = Attribute("ShadowSigmaExtWalls",
+            "Standard deviation of the normal distribution used for calculate the shadowing due to ext walls ",
+            type = Types.Double,
+            default = "5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_shadowsigmaextwalls)
+
+        attr_internalwallloss = Attribute("InternalWallLoss",
+            "Additional loss for each internal wall [dB]",
+            type = Types.Double,
+            default = "5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_internalwallloss)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3HybridBuildingsPropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-hybrid-buildings-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/icmpv4l4protocol.py b/src/nepi/resources/ns3/classes/icmpv4l4protocol.py
new file mode 100644 (file)
index 0000000..202137f
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3icmpv4l4protocol import NS3BaseIcmpv4L4Protocol 
+
+@clsinit_copy
+class NS3Icmpv4L4Protocol(NS3BaseIcmpv4L4Protocol):
+    _rtype = "ns3::Icmpv4L4Protocol"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_protocolnumber = Attribute("ProtocolNumber",
+            "The Ip protocol number.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_protocolnumber)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3Icmpv4L4Protocol, self).__init__(ec, guid)
+        self._home = "ns3-icmpv4l4protocol-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/icmpv6l4protocol.py b/src/nepi/resources/ns3/classes/icmpv6l4protocol.py
new file mode 100644 (file)
index 0000000..23e37b1
--- /dev/null
@@ -0,0 +1,70 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3Icmpv6L4Protocol(NS3Base):
+    _rtype = "ns3::Icmpv6L4Protocol"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_dad = Attribute("DAD",
+            "Always do DAD check.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_dad)
+
+        attr_solicitationjitter = Attribute("SolicitationJitter",
+            "The jitter in ms a node is allowed to wait before sending any solicitation . Some jitter aims to prevent collisions. By default, the model will wait for a duration in ms defined by a uniform random-variable between 0 and SolicitationJitter",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=0.0|Max=10.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_solicitationjitter)
+
+        attr_protocolnumber = Attribute("ProtocolNumber",
+            "The Ip protocol number.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_protocolnumber)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3Icmpv6L4Protocol, self).__init__(ec, guid)
+        self._home = "ns3-icmpv6l4protocol-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/ideal_wifi_manager.py b/src/nepi/resources/ns3/classes/ideal_wifi_manager.py
new file mode 100644 (file)
index 0000000..e384184
--- /dev/null
@@ -0,0 +1,137 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3IdealWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::IdealWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_berthreshold = Attribute("BerThreshold",
+            "The maximum Bit Error Rate acceptable at any transmission mode",
+            type = Types.Double,
+            default = "1e-05",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_berthreshold)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3IdealWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-ideal-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/ipv4l3protocol.py b/src/nepi/resources/ns3/classes/ipv4l3protocol.py
new file mode 100644 (file)
index 0000000..8c7228d
--- /dev/null
@@ -0,0 +1,115 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3ipv4l3protocol import NS3BaseIpv4L3Protocol 
+
+@clsinit_copy
+class NS3Ipv4L3Protocol(NS3BaseIpv4L3Protocol):
+    _rtype = "ns3::Ipv4L3Protocol"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_defaulttos = Attribute("DefaultTos",
+            "The TOS value set by default on all outgoing packets generated on this node.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttos)
+
+        attr_defaultttl = Attribute("DefaultTtl",
+            "The TTL value set by default on all outgoing packets generated on this node.",
+            type = Types.Integer,
+            default = "64",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaultttl)
+
+        attr_fragmentexpirationtimeout = Attribute("FragmentExpirationTimeout",
+            "When this timeout expires, the fragments will be cleared from the buffer.",
+            type = Types.String,
+            default = "+30000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentexpirationtimeout)
+
+        attr_ipforward = Attribute("IpForward",
+            "Globally enable or disable IP forwarding for all current and future Ipv4 devices.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ipforward)
+
+        attr_weakesmodel = Attribute("WeakEsModel",
+            "RFC1122 term for whether host accepts datagram with a dest. address on another interface",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_weakesmodel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        tx = Trace("Tx", "Send ipv4 packet to outgoing interface.")
+
+        cls._register_trace(tx)
+
+        rx = Trace("Rx", "Receive ipv4 packet from incoming interface.")
+
+        cls._register_trace(rx)
+
+        drop = Trace("Drop", "Drop ipv4 packet")
+
+        cls._register_trace(drop)
+
+        sendoutgoing = Trace("SendOutgoing", "A newly-generated packet by this node is about to be queued for transmission")
+
+        cls._register_trace(sendoutgoing)
+
+        unicastforward = Trace("UnicastForward", "A unicast IPv4 packet was received by this node and is being forwarded to another node")
+
+        cls._register_trace(unicastforward)
+
+        localdeliver = Trace("LocalDeliver", "An IPv4 packet was received by/for this node, and it is being forward up the stack")
+
+        cls._register_trace(localdeliver)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3Ipv4L3Protocol, self).__init__(ec, guid)
+        self._home = "ns3-ipv4l3protocol-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/jakes_propagation_loss_model.py b/src/nepi/resources/ns3/classes/jakes_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..af4729c
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3JakesPropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::JakesPropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        pass
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3JakesPropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-jakes-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/list_error_model.py b/src/nepi/resources/ns3/classes/list_error_model.py
new file mode 100644 (file)
index 0000000..a607117
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+class NS3ListErrorModel(NS3BaseErrorModel):
+    _rtype = "ns3::ListErrorModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_isenabled = Attribute("IsEnabled",
+            "Whether this ErrorModel is enabled or not.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_isenabled)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3ListErrorModel, self).__init__(ec, guid)
+        self._home = "ns3-list-error-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/log_distance_propagation_loss_model.py b/src/nepi/resources/ns3/classes/log_distance_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..5f3c5fd
--- /dev/null
@@ -0,0 +1,70 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3LogDistancePropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::LogDistancePropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_exponent = Attribute("Exponent",
+            "The exponent of the Path Loss propagation model",
+            type = Types.Double,
+            default = "3",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_exponent)
+
+        attr_referencedistance = Attribute("ReferenceDistance",
+            "The distance at which the reference loss is calculated (m)",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_referencedistance)
+
+        attr_referenceloss = Attribute("ReferenceLoss",
+            "The reference loss at reference distance (dB). (Default is Friis at 1m with 5.15 GHz)",
+            type = Types.Double,
+            default = "46.6777",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_referenceloss)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3LogDistancePropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-log-distance-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/loopback_net_device.py b/src/nepi/resources/ns3/classes/loopback_net_device.py
new file mode 100644 (file)
index 0000000..a9e6162
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3LoopbackNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::LoopbackNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        pass
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3LoopbackNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-loopback-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/lte_enb_net_device.py b/src/nepi/resources/ns3/classes/lte_enb_net_device.py
new file mode 100644 (file)
index 0000000..f1ac832
--- /dev/null
@@ -0,0 +1,100 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3LteEnbNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::LteEnbNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_ulbandwidth = Attribute("UlBandwidth",
+            "Uplink Transmission Bandwidth Configuration in number of Resource Blocks",
+            type = Types.Integer,
+            default = "25",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ulbandwidth)
+
+        attr_dlbandwidth = Attribute("DlBandwidth",
+            "Downlink Transmission Bandwidth Configuration in number of Resource Blocks",
+            type = Types.Integer,
+            default = "25",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_dlbandwidth)
+
+        attr_cellid = Attribute("CellId",
+            "Cell Identifier",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_cellid)
+
+        attr_dlearfcn = Attribute("DlEarfcn",
+            "Downlink E-UTRA Absolute Radio Frequency Channel Number (EARFCN) as per 3GPP 36.101 Section 5.7.3. ",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_dlearfcn)
+
+        attr_ulearfcn = Attribute("UlEarfcn",
+            "Uplink E-UTRA Absolute Radio Frequency Channel Number (EARFCN) as per 3GPP 36.101 Section 5.7.3. ",
+            type = Types.Integer,
+            default = "18100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ulearfcn)
+
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "30000",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3LteEnbNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-lte-enb-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/lte_simple_net_device.py b/src/nepi/resources/ns3/classes/lte_simple_net_device.py
new file mode 100644 (file)
index 0000000..b38a7e9
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3LteSimpleNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::LteSimpleNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        pass
+
+    @classmethod
+    def _register_traces(cls):
+        
+        phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception")
+
+        cls._register_trace(phyrxdrop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3LteSimpleNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-lte-simple-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/matrix_propagation_loss_model.py b/src/nepi/resources/ns3/classes/matrix_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..4d14e14
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3MatrixPropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::MatrixPropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_defaultloss = Attribute("DefaultLoss",
+            "The default value for propagation loss, dB.",
+            type = Types.Double,
+            default = "1.79769e+308",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaultloss)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3MatrixPropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-matrix-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/mesh_point_device.py b/src/nepi/resources/ns3/classes/mesh_point_device.py
new file mode 100644 (file)
index 0000000..945952a
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3MeshPointDevice(NS3BaseNetDevice):
+    _rtype = "ns3::MeshPointDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "65535",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3MeshPointDevice, self).__init__(ec, guid)
+        self._home = "ns3-mesh-point-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/mesh_wifi_interface_mac.py b/src/nepi/resources/ns3/classes/mesh_wifi_interface_mac.py
new file mode 100644 (file)
index 0000000..b736081
--- /dev/null
@@ -0,0 +1,239 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
+
+@clsinit_copy
+class NS3MeshWifiInterfaceMac(NS3BaseWifiMac):
+    _rtype = "ns3::MeshWifiInterfaceMac"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_beaconinterval = Attribute("BeaconInterval",
+            "Beacon Interval",
+            type = Types.String,
+            default = "+500000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_beaconinterval)
+
+        attr_randomstart = Attribute("RandomStart",
+            "Window when beacon generating starts (uniform random) in seconds",
+            type = Types.String,
+            default = "+500000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_randomstart)
+
+        attr_beacongeneration = Attribute("BeaconGeneration",
+            "Enable/Disable Beaconing.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_beacongeneration)
+
+        attr_qossupported = Attribute("QosSupported",
+            "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_qossupported)
+
+        attr_htsupported = Attribute("HtSupported",
+            "This Boolean attribute is set to enable 802.11n support at this STA",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_htsupported)
+
+        attr_ctstoselfsupported = Attribute("CtsToSelfSupported",
+            "Use CTS to Self when using a rate that is not in the basic set rate",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ctstoselfsupported)
+
+        attr_ctstimeout = Attribute("CtsTimeout",
+            "When this timeout expires, the RTS/CTS handshake has failed.",
+            type = Types.String,
+            default = "+75000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ctstimeout)
+
+        attr_acktimeout = Attribute("AckTimeout",
+            "When this timeout expires, the DATA/ACK handshake has failed.",
+            type = Types.String,
+            default = "+75000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_acktimeout)
+
+        attr_basicblockacktimeout = Attribute("BasicBlockAckTimeout",
+            "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.",
+            type = Types.String,
+            default = "+281000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_basicblockacktimeout)
+
+        attr_compressedblockacktimeout = Attribute("CompressedBlockAckTimeout",
+            "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.",
+            type = Types.String,
+            default = "+107000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_compressedblockacktimeout)
+
+        attr_sifs = Attribute("Sifs",
+            "The value of the SIFS constant.",
+            type = Types.String,
+            default = "+16000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_sifs)
+
+        attr_eifsnodifs = Attribute("EifsNoDifs",
+            "The value of EIFS-DIFS",
+            type = Types.String,
+            default = "+60000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_eifsnodifs)
+
+        attr_slot = Attribute("Slot",
+            "The duration of a Slot.",
+            type = Types.String,
+            default = "+9000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_slot)
+
+        attr_pifs = Attribute("Pifs",
+            "The value of the PIFS constant.",
+            type = Types.String,
+            default = "+25000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pifs)
+
+        attr_rifs = Attribute("Rifs",
+            "The value of the RIFS constant.",
+            type = Types.String,
+            default = "+2000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rifs)
+
+        attr_maxpropagationdelay = Attribute("MaxPropagationDelay",
+            "The maximum propagation delay. Unused for now.",
+            type = Types.String,
+            default = "+3333.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpropagationdelay)
+
+        attr_ssid = Attribute("Ssid",
+            "The ssid we want to belong to.",
+            type = Types.String,
+            default = "default",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ssid)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        txokheader = Trace("TxOkHeader", "The header of successfully transmitted packet")
+
+        cls._register_trace(txokheader)
+
+        txerrheader = Trace("TxErrHeader", "The header of unsuccessfully transmitted packet")
+
+        cls._register_trace(txerrheader)
+
+        mactx = Trace("MacTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.")
+
+        cls._register_trace(mactx)
+
+        mactxdrop = Trace("MacTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.")
+
+        cls._register_trace(mactxdrop)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+        macrxdrop = Trace("MacRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.")
+
+        cls._register_trace(macrxdrop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3MeshWifiInterfaceMac, self).__init__(ec, guid)
+        self._home = "ns3-mesh-wifi-interface-mac-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/minstrel_wifi_manager.py b/src/nepi/resources/ns3/classes/minstrel_wifi_manager.py
new file mode 100644 (file)
index 0000000..3818645
--- /dev/null
@@ -0,0 +1,177 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3MinstrelWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::MinstrelWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_updatestatistics = Attribute("UpdateStatistics",
+            "The interval between updating statistics table ",
+            type = Types.String,
+            default = "+100000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_updatestatistics)
+
+        attr_lookaroundrate = Attribute("LookAroundRate",
+            "the percentage to try other rates",
+            type = Types.Double,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_lookaroundrate)
+
+        attr_ewma = Attribute("EWMA",
+            "EWMA level",
+            type = Types.Double,
+            default = "75",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ewma)
+
+        attr_samplecolumn = Attribute("SampleColumn",
+            "The number of columns used for sampling",
+            type = Types.Double,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_samplecolumn)
+
+        attr_packetlength = Attribute("PacketLength",
+            "The packet length used for calculating mode TxTime",
+            type = Types.Double,
+            default = "1200",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_packetlength)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3MinstrelWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-minstrel-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/multi_model_spectrum_channel.py b/src/nepi/resources/ns3/classes/multi_model_spectrum_channel.py
new file mode 100644 (file)
index 0000000..c8d6e64
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3MultiModelSpectrumChannel(NS3BaseChannel):
+    _rtype = "ns3::MultiModelSpectrumChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_maxlossdb = Attribute("MaxLossDb",
+            "If a single-frequency PropagationLossModel is used, this value represents the maximum loss in dB for which transmissions will be passed to the receiving PHY. Signals for which the PropagationLossModel returns a loss bigger than this value will not be propagated to the receiver. This parameter is to be used to reduce the computational load by not propagating signals that are far beyond the interference range. Note that the default value corresponds to considering all signals for reception. Tune this value with care. ",
+            type = Types.Double,
+            default = "1e+09",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxlossdb)
+
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        pathloss = Trace("PathLoss", "This trace is fired whenever a new path loss value is calculated. The first and second parameters to the trace are pointers respectively to the TX and RX SpectrumPhy instances, whereas the third parameters is the loss value in dB. Note that the loss value reported by this trace is the single-frequency loss value obtained by evaluating only the TX and RX AntennaModels and the PropagationLossModel. In particular, note that SpectrumPropagationLossModel (even if present) is never used to evaluate the loss value reported in this trace. ")
+
+        cls._register_trace(pathloss)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3MultiModelSpectrumChannel, self).__init__(ec, guid)
+        self._home = "ns3-multi-model-spectrum-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/nakagami_propagation_loss_model.py b/src/nepi/resources/ns3/classes/nakagami_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..371a895
--- /dev/null
@@ -0,0 +1,110 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3NakagamiPropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::NakagamiPropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_distance1 = Attribute("Distance1",
+            "Beginning of the second distance field. Default is 80m.",
+            type = Types.Double,
+            default = "80",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_distance1)
+
+        attr_distance2 = Attribute("Distance2",
+            "Beginning of the third distance field. Default is 200m.",
+            type = Types.Double,
+            default = "200",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_distance2)
+
+        attr_m0 = Attribute("m0",
+            "m0 for distances smaller than Distance1. Default is 1.5.",
+            type = Types.Double,
+            default = "1.5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_m0)
+
+        attr_m1 = Attribute("m1",
+            "m1 for distances smaller than Distance2. Default is 0.75.",
+            type = Types.Double,
+            default = "0.75",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_m1)
+
+        attr_m2 = Attribute("m2",
+            "m2 for distances greater than Distance2. Default is 0.75.",
+            type = Types.Double,
+            default = "0.75",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_m2)
+
+        attr_erlangrv = Attribute("ErlangRv",
+            "Access to the underlying ErlangRandomVariable",
+            type = Types.String,
+            default = "ns3::ErlangRandomVariable",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_erlangrv)
+
+        attr_gammarv = Attribute("GammaRv",
+            "Access to the underlying GammaRandomVariable",
+            type = Types.String,
+            default = "ns3::GammaRandomVariable",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_gammarv)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3NakagamiPropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-nakagami-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/nist_error_rate_model.py b/src/nepi/resources/ns3/classes/nist_error_rate_model.py
new file mode 100644 (file)
index 0000000..5a433b4
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3errorratemodel import NS3BaseErrorRateModel 
+
+@clsinit_copy
+class NS3NistErrorRateModel(NS3BaseErrorRateModel):
+    _rtype = "ns3::NistErrorRateModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        pass
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3NistErrorRateModel, self).__init__(ec, guid)
+        self._home = "ns3-nist-error-rate-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/node.py b/src/nepi/resources/ns3/classes/node.py
new file mode 100644 (file)
index 0000000..f758192
--- /dev/null
@@ -0,0 +1,60 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3node import NS3BaseNode 
+
+@clsinit_copy
+class NS3Node(NS3BaseNode):
+    _rtype = "ns3::Node"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Node.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+        attr_systemid = Attribute("SystemId",
+            "The systemId of this node: a unique integer used for parallel simulations.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_systemid)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3Node, self).__init__(ec, guid)
+        self._home = "ns3-node-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/non_communicating_net_device.py b/src/nepi/resources/ns3/classes/non_communicating_net_device.py
new file mode 100644 (file)
index 0000000..4fb08e7
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3NonCommunicatingNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::NonCommunicatingNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        pass
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3NonCommunicatingNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-non-communicating-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.py b/src/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..530d9ae
--- /dev/null
@@ -0,0 +1,80 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3OhBuildingsPropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::OhBuildingsPropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_shadowsigmaoutdoor = Attribute("ShadowSigmaOutdoor",
+            "Standard deviation of the normal distribution used for calculate the shadowing for outdoor nodes",
+            type = Types.Double,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_shadowsigmaoutdoor)
+
+        attr_shadowsigmaindoor = Attribute("ShadowSigmaIndoor",
+            "Standard deviation of the normal distribution used for calculate the shadowing for indoor nodes ",
+            type = Types.Double,
+            default = "8",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_shadowsigmaindoor)
+
+        attr_shadowsigmaextwalls = Attribute("ShadowSigmaExtWalls",
+            "Standard deviation of the normal distribution used for calculate the shadowing due to ext walls ",
+            type = Types.Double,
+            default = "5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_shadowsigmaextwalls)
+
+        attr_internalwallloss = Attribute("InternalWallLoss",
+            "Additional loss for each internal wall [dB]",
+            type = Types.Double,
+            default = "5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_internalwallloss)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3OhBuildingsPropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-oh-buildings-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/on_off_application.py b/src/nepi/resources/ns3/classes/on_off_application.py
new file mode 100644 (file)
index 0000000..ffae8e9
--- /dev/null
@@ -0,0 +1,135 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3OnOffApplication(NS3BaseApplication):
+    _rtype = "ns3::OnOffApplication"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_datarate = Attribute("DataRate",
+            "The data rate in on state.",
+            type = Types.String,
+            default = "500000bps",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_datarate)
+
+        attr_packetsize = Attribute("PacketSize",
+            "The size of packets sent in on state",
+            type = Types.Integer,
+            default = "512",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_packetsize)
+
+        attr_remote = Attribute("Remote",
+            "The address of the destination",
+            type = Types.String,
+            default = "00-00-00",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remote)
+
+        attr_ontime = Attribute("OnTime",
+            "A RandomVariableStream used to pick the duration of the \'On\' state.",
+            type = Types.String,
+            default = "ns3::ConstantRandomVariable[Constant=1.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ontime)
+
+        attr_offtime = Attribute("OffTime",
+            "A RandomVariableStream used to pick the duration of the \'Off\' state.",
+            type = Types.String,
+            default = "ns3::ConstantRandomVariable[Constant=1.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_offtime)
+
+        attr_maxbytes = Attribute("MaxBytes",
+            "The total number of bytes to send. Once these bytes are sent, no packet is sent again, even in on state. The value zero means that there is no limit.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxbytes)
+
+        attr_protocol = Attribute("Protocol",
+            "The type of protocol to use.",
+            type = Types.String,
+            default = "ns3::UdpSocketFactory",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_protocol)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        tx = Trace("Tx", "A new packet is created and is sent")
+
+        cls._register_trace(tx)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3OnOffApplication, self).__init__(ec, guid)
+        self._home = "ns3-on-off-application-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/onoe_wifi_manager.py b/src/nepi/resources/ns3/classes/onoe_wifi_manager.py
new file mode 100644 (file)
index 0000000..606b3e8
--- /dev/null
@@ -0,0 +1,157 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3OnoeWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::OnoeWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_updateperiod = Attribute("UpdatePeriod",
+            "The interval between decisions about rate control changes",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_updateperiod)
+
+        attr_raisethreshold = Attribute("RaiseThreshold",
+            "Attempt to raise the rate if we hit that threshold",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_raisethreshold)
+
+        attr_addcreditthreshold = Attribute("AddCreditThreshold",
+            "Add credit threshold",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_addcreditthreshold)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3OnoeWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-onoe-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/packet_sink.py b/src/nepi/resources/ns3/classes/packet_sink.py
new file mode 100644 (file)
index 0000000..701c8d0
--- /dev/null
@@ -0,0 +1,85 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3PacketSink(NS3BaseApplication):
+    _rtype = "ns3::PacketSink"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_local = Attribute("Local",
+            "The Address on which to Bind the rx socket.",
+            type = Types.String,
+            default = "00-00-00",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_local)
+
+        attr_protocol = Attribute("Protocol",
+            "The type id of the protocol to use for the rx socket.",
+            type = Types.String,
+            default = "ns3::UdpSocketFactory",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_protocol)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        rx = Trace("Rx", "A packet has been received")
+
+        cls._register_trace(rx)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3PacketSink, self).__init__(ec, guid)
+        self._home = "ns3-packet-sink-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/ping6.py b/src/nepi/resources/ns3/classes/ping6.py
new file mode 100644 (file)
index 0000000..7986532
--- /dev/null
@@ -0,0 +1,110 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3Ping6(NS3BaseApplication):
+    _rtype = "ns3::Ping6"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_maxpackets = Attribute("MaxPackets",
+            "The maximum number of packets the application will send",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpackets)
+
+        attr_interval = Attribute("Interval",
+            "The time to wait between packets",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_interval)
+
+        attr_remoteipv6 = Attribute("RemoteIpv6",
+            "The Ipv6Address of the outbound packets",
+            type = Types.String,
+            default = "0000:0000:0000:0000:0000:0000:0000:0000",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remoteipv6)
+
+        attr_localipv6 = Attribute("LocalIpv6",
+            "Local Ipv6Address of the sender",
+            type = Types.String,
+            default = "0000:0000:0000:0000:0000:0000:0000:0000",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_localipv6)
+
+        attr_packetsize = Attribute("PacketSize",
+            "Size of packets generated",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_packetsize)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3Ping6, self).__init__(ec, guid)
+        self._home = "ns3-ping6-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/point_to_point_channel.py b/src/nepi/resources/ns3/classes/point_to_point_channel.py
new file mode 100644 (file)
index 0000000..e943fc7
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3PointToPointChannel(NS3BaseChannel):
+    _rtype = "ns3::PointToPointChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_delay = Attribute("Delay",
+            "Transmission delay through the channel",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_delay)
+
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        txrxpointtopoint = Trace("TxRxPointToPoint", "Trace source indicating transmission of packet from the PointToPointChannel, used by the Animation interface.")
+
+        cls._register_trace(txrxpointtopoint)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3PointToPointChannel, self).__init__(ec, guid)
+        self._home = "ns3-point-to-point-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/point_to_point_net_device.py b/src/nepi/resources/ns3/classes/point_to_point_net_device.py
new file mode 100644 (file)
index 0000000..699a785
--- /dev/null
@@ -0,0 +1,125 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3PointToPointNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::PointToPointNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "1500",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+        attr_address = Attribute("Address",
+            "The MAC address of this device.",
+            type = Types.String,
+            default = "ff:ff:ff:ff:ff:ff",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_address)
+
+        attr_datarate = Attribute("DataRate",
+            "The default data rate for point to point links",
+            type = Types.String,
+            default = "32768bps",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_datarate)
+
+        attr_interframegap = Attribute("InterframeGap",
+            "The time to wait between packet (frame) transmissions",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_interframegap)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device")
+
+        cls._register_trace(mactx)
+
+        mactxdrop = Trace("MacTxDrop", "Trace source indicating a packet has been dropped by the device before transmission")
+
+        cls._register_trace(mactxdrop)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+        phytxbegin = Trace("PhyTxBegin", "Trace source indicating a packet has begun transmitting over the channel")
+
+        cls._register_trace(phytxbegin)
+
+        phytxend = Trace("PhyTxEnd", "Trace source indicating a packet has been completely transmitted over the channel")
+
+        cls._register_trace(phytxend)
+
+        phytxdrop = Trace("PhyTxDrop", "Trace source indicating a packet has been dropped by the device during transmission")
+
+        cls._register_trace(phytxdrop)
+
+        phyrxend = Trace("PhyRxEnd", "Trace source indicating a packet has been completely received by the device")
+
+        cls._register_trace(phyrxend)
+
+        phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception")
+
+        cls._register_trace(phyrxdrop)
+
+        sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(sniffer)
+
+        promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(promiscsniffer)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3PointToPointNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-point-to-point-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/point_to_point_remote_channel.py b/src/nepi/resources/ns3/classes/point_to_point_remote_channel.py
new file mode 100644 (file)
index 0000000..2c3ccf1
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3PointToPointRemoteChannel(NS3BaseChannel):
+    _rtype = "ns3::PointToPointRemoteChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_delay = Attribute("Delay",
+            "Transmission delay through the channel",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_delay)
+
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        txrxpointtopoint = Trace("TxRxPointToPoint", "Trace source indicating transmission of packet from the PointToPointChannel, used by the Animation interface.")
+
+        cls._register_trace(txrxpointtopoint)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3PointToPointRemoteChannel, self).__init__(ec, guid)
+        self._home = "ns3-point-to-point-remote-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/radvd.py b/src/nepi/resources/ns3/classes/radvd.py
new file mode 100644 (file)
index 0000000..d9ac187
--- /dev/null
@@ -0,0 +1,70 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3Radvd(NS3BaseApplication):
+    _rtype = "ns3::Radvd"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_advertisementjitter = Attribute("AdvertisementJitter",
+            "Uniform variable to provide jitter between min and max values of AdvInterval",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_advertisementjitter)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3Radvd, self).__init__(ec, guid)
+        self._home = "ns3-radvd-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/random_direction2d_mobility_model.py b/src/nepi/resources/ns3/classes/random_direction2d_mobility_model.py
new file mode 100644 (file)
index 0000000..6d2e75d
--- /dev/null
@@ -0,0 +1,95 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3RandomDirection2dMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::RandomDirection2dMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_bounds = Attribute("Bounds",
+            "The 2d bounding area",
+            type = Types.String,
+            default = "-100|100|-100|100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_bounds)
+
+        attr_speed = Attribute("Speed",
+            "A random variable to control the speed (m/s).",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=1.0|Max=2.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_speed)
+
+        attr_pause = Attribute("Pause",
+            "A random variable to control the pause (s).",
+            type = Types.String,
+            default = "ns3::ConstantRandomVariable[Constant=2.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pause)
+
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3RandomDirection2dMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-random-direction2d-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/random_propagation_delay_model.py b/src/nepi/resources/ns3/classes/random_propagation_delay_model.py
new file mode 100644 (file)
index 0000000..30a5f29
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationdelaymodel import NS3BasePropagationDelayModel 
+
+@clsinit_copy
+class NS3RandomPropagationDelayModel(NS3BasePropagationDelayModel):
+    _rtype = "ns3::RandomPropagationDelayModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_variable = Attribute("Variable",
+            "The random variable which generates random delays (s).",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_variable)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3RandomPropagationDelayModel, self).__init__(ec, guid)
+        self._home = "ns3-random-propagation-delay-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/random_propagation_loss_model.py b/src/nepi/resources/ns3/classes/random_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..05f0228
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3RandomPropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::RandomPropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_variable = Attribute("Variable",
+            "The random variable used to pick a loss everytime CalcRxPower is invoked.",
+            type = Types.String,
+            default = "ns3::ConstantRandomVariable[Constant=1.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_variable)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3RandomPropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-random-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/random_walk2d_mobility_model.py b/src/nepi/resources/ns3/classes/random_walk2d_mobility_model.py
new file mode 100644 (file)
index 0000000..ee4095a
--- /dev/null
@@ -0,0 +1,125 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3RandomWalk2dMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::RandomWalk2dMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_bounds = Attribute("Bounds",
+            "Bounds of the area to cruise.",
+            type = Types.String,
+            default = "0|0|100|100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_bounds)
+
+        attr_time = Attribute("Time",
+            "Change current direction and speed after moving for this delay.",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_time)
+
+        attr_distance = Attribute("Distance",
+            "Change current direction and speed after moving for this distance.",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_distance)
+
+        attr_mode = Attribute("Mode",
+            "The mode indicates the condition used to change the current speed and direction",
+            type = Types.Enumerate,
+            default = "Distance",  
+            allowed = ["Distance","Time"],
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mode)
+
+        attr_direction = Attribute("Direction",
+            "A random variable used to pick the direction (gradients).",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=0.0|Max=6.283184]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_direction)
+
+        attr_speed = Attribute("Speed",
+            "A random variable used to pick the speed (m/s).",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=2.0|Max=4.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_speed)
+
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3RandomWalk2dMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-random-walk2d-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/random_waypoint_mobility_model.py b/src/nepi/resources/ns3/classes/random_waypoint_mobility_model.py
new file mode 100644 (file)
index 0000000..6ca4a27
--- /dev/null
@@ -0,0 +1,85 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3RandomWaypointMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::RandomWaypointMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_speed = Attribute("Speed",
+            "A random variable used to pick the speed of a random waypoint model.",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=0.3|Max=0.7]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_speed)
+
+        attr_pause = Attribute("Pause",
+            "A random variable used to pick the pause of a random waypoint model.",
+            type = Types.String,
+            default = "ns3::ConstantRandomVariable[Constant=2.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pause)
+
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3RandomWaypointMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-random-waypoint-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/range_propagation_loss_model.py b/src/nepi/resources/ns3/classes/range_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..529e520
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3RangePropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::RangePropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_maxrange = Attribute("MaxRange",
+            "Maximum Transmission Range (meters)",
+            type = Types.Double,
+            default = "250",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxrange)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3RangePropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-range-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/rate_error_model.py b/src/nepi/resources/ns3/classes/rate_error_model.py
new file mode 100644 (file)
index 0000000..2d56a34
--- /dev/null
@@ -0,0 +1,80 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+class NS3RateErrorModel(NS3BaseErrorModel):
+    _rtype = "ns3::RateErrorModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_errorunit = Attribute("ErrorUnit",
+            "The error unit",
+            type = Types.Enumerate,
+            default = "ERROR_UNIT_BYTE",  
+            allowed = ["ERROR_UNIT_BIT","ERROR_UNIT_BYTE","ERROR_UNIT_PACKET"],
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_errorunit)
+
+        attr_errorrate = Attribute("ErrorRate",
+            "The error rate.",
+            type = Types.Double,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_errorrate)
+
+        attr_ranvar = Attribute("RanVar",
+            "The decision variable attached to this error model.",
+            type = Types.String,
+            default = "ns3::UniformRandomVariable[Min=0.0|Max=1.0]",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ranvar)
+
+        attr_isenabled = Attribute("IsEnabled",
+            "Whether this ErrorModel is enabled or not.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_isenabled)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3RateErrorModel, self).__init__(ec, guid)
+        self._home = "ns3-rate-error-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/receive_list_error_model.py b/src/nepi/resources/ns3/classes/receive_list_error_model.py
new file mode 100644 (file)
index 0000000..2f1652c
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+class NS3ReceiveListErrorModel(NS3BaseErrorModel):
+    _rtype = "ns3::ReceiveListErrorModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_isenabled = Attribute("IsEnabled",
+            "Whether this ErrorModel is enabled or not.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_isenabled)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3ReceiveListErrorModel, self).__init__(ec, guid)
+        self._home = "ns3-receive-list-error-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/red_queue.py b/src/nepi/resources/ns3/classes/red_queue.py
new file mode 100644 (file)
index 0000000..d68166e
--- /dev/null
@@ -0,0 +1,173 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3queue import NS3BaseQueue 
+
+@clsinit_copy
+class NS3RedQueue(NS3BaseQueue):
+    _rtype = "ns3::RedQueue"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_meanpktsize = Attribute("MeanPktSize",
+            "Average of packet size",
+            type = Types.Integer,
+            default = "500",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_meanpktsize)
+
+        attr_idlepktsize = Attribute("IdlePktSize",
+            "Average packet size used during idle times. Used when m_cautions = 3",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_idlepktsize)
+
+        attr_wait = Attribute("Wait",
+            "True for waiting between dropped packets",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_wait)
+
+        attr_gentle = Attribute("Gentle",
+            "True to increases dropping probability slowly when average queue exceeds maxthresh",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_gentle)
+
+        attr_minth = Attribute("MinTh",
+            "Minimum average length threshold in packets/bytes",
+            type = Types.Double,
+            default = "5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_minth)
+
+        attr_maxth = Attribute("MaxTh",
+            "Maximum average length threshold in packets/bytes",
+            type = Types.Double,
+            default = "15",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxth)
+
+        attr_queuelimit = Attribute("QueueLimit",
+            "Queue limit in bytes/packets",
+            type = Types.Integer,
+            default = "25",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_queuelimit)
+
+        attr_qw = Attribute("QW",
+            "Queue weight related to the exponential weighted moving average (EWMA)",
+            type = Types.Double,
+            default = "0.002",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_qw)
+
+        attr_linterm = Attribute("LInterm",
+            "The maximum probability of dropping a packet",
+            type = Types.Double,
+            default = "50",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_linterm)
+
+        attr_ns1compat = Attribute("Ns1Compat",
+            "NS-1 compatibility",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ns1compat)
+
+        attr_linkbandwidth = Attribute("LinkBandwidth",
+            "The RED link bandwidth",
+            type = Types.String,
+            default = "1500000bps",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_linkbandwidth)
+
+        attr_linkdelay = Attribute("LinkDelay",
+            "The RED link delay",
+            type = Types.String,
+            default = "+20000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_linkdelay)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        enqueue = Trace("Enqueue", "Enqueue a packet in the queue.")
+
+        cls._register_trace(enqueue)
+
+        dequeue = Trace("Dequeue", "Dequeue a packet from the queue.")
+
+        cls._register_trace(dequeue)
+
+        drop = Trace("Drop", "Drop a packet stored in the queue.")
+
+        cls._register_trace(drop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3RedQueue, self).__init__(ec, guid)
+        self._home = "ns3-red-queue-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/rraa_wifi_manager.py b/src/nepi/resources/ns3/classes/rraa_wifi_manager.py
new file mode 100644 (file)
index 0000000..1553b8a
--- /dev/null
@@ -0,0 +1,367 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+class NS3RraaWifiManager(NS3BaseWifiRemoteStationManager):
+    _rtype = "ns3::RraaWifiManager"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_basic = Attribute("Basic",
+            "If true the RRAA-BASIC algorithm will be used, otherwise the RRAA wil be used",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_basic)
+
+        attr_timeout = Attribute("Timeout",
+            "Timeout for the RRAA BASIC loss estimaton block (s)",
+            type = Types.String,
+            default = "+50000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_timeout)
+
+        attr_ewndfor54mbps = Attribute("ewndFor54mbps",
+            "ewnd parameter for 54 Mbs data mode",
+            type = Types.Integer,
+            default = "40",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ewndfor54mbps)
+
+        attr_ewndfor48mbps = Attribute("ewndFor48mbps",
+            "ewnd parameter for 48 Mbs data mode",
+            type = Types.Integer,
+            default = "40",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ewndfor48mbps)
+
+        attr_ewndfor36mbps = Attribute("ewndFor36mbps",
+            "ewnd parameter for 36 Mbs data mode",
+            type = Types.Integer,
+            default = "40",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ewndfor36mbps)
+
+        attr_ewndfor24mbps = Attribute("ewndFor24mbps",
+            "ewnd parameter for 24 Mbs data mode",
+            type = Types.Integer,
+            default = "40",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ewndfor24mbps)
+
+        attr_ewndfor18mbps = Attribute("ewndFor18mbps",
+            "ewnd parameter for 18 Mbs data mode",
+            type = Types.Integer,
+            default = "20",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ewndfor18mbps)
+
+        attr_ewndfor12mbps = Attribute("ewndFor12mbps",
+            "ewnd parameter for 12 Mbs data mode",
+            type = Types.Integer,
+            default = "20",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ewndfor12mbps)
+
+        attr_ewndfor9mbps = Attribute("ewndFor9mbps",
+            "ewnd parameter for 9 Mbs data mode",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ewndfor9mbps)
+
+        attr_ewndfor6mbps = Attribute("ewndFor6mbps",
+            "ewnd parameter for 6 Mbs data mode",
+            type = Types.Integer,
+            default = "6",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ewndfor6mbps)
+
+        attr_porifor48mbps = Attribute("poriFor48mbps",
+            "Pori parameter for 48 Mbs data mode",
+            type = Types.Double,
+            default = "0.047",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_porifor48mbps)
+
+        attr_porifor36mbps = Attribute("poriFor36mbps",
+            "Pori parameter for 36 Mbs data mode",
+            type = Types.Double,
+            default = "0.115",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_porifor36mbps)
+
+        attr_porifor24mbps = Attribute("poriFor24mbps",
+            "Pori parameter for 24 Mbs data mode",
+            type = Types.Double,
+            default = "0.1681",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_porifor24mbps)
+
+        attr_porifor18mbps = Attribute("poriFor18mbps",
+            "Pori parameter for 18 Mbs data mode",
+            type = Types.Double,
+            default = "0.1325",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_porifor18mbps)
+
+        attr_porifor12mbps = Attribute("poriFor12mbps",
+            "Pori parameter for 12 Mbs data mode",
+            type = Types.Double,
+            default = "0.1861",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_porifor12mbps)
+
+        attr_porifor9mbps = Attribute("poriFor9mbps",
+            "Pori parameter for 9 Mbs data mode",
+            type = Types.Double,
+            default = "0.1434",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_porifor9mbps)
+
+        attr_porifor6mbps = Attribute("poriFor6mbps",
+            "Pori parameter for 6 Mbs data mode",
+            type = Types.Double,
+            default = "0.5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_porifor6mbps)
+
+        attr_pmtlfor54mbps = Attribute("pmtlFor54mbps",
+            "Pmtl parameter for 54 Mbs data mode",
+            type = Types.Double,
+            default = "0.094",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pmtlfor54mbps)
+
+        attr_pmtlfor48mbps = Attribute("pmtlFor48mbps",
+            "Pmtl parameter for 48 Mbs data mode",
+            type = Types.Double,
+            default = "0.23",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pmtlfor48mbps)
+
+        attr_pmtlfor36mbps = Attribute("pmtlFor36mbps",
+            "Pmtl parameter for 36 Mbs data mode",
+            type = Types.Double,
+            default = "0.3363",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pmtlfor36mbps)
+
+        attr_pmtlfor24mbps = Attribute("pmtlFor24mbps",
+            "Pmtl parameter for 24 Mbs data mode",
+            type = Types.Double,
+            default = "0.265",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pmtlfor24mbps)
+
+        attr_pmtlfor18mbps = Attribute("pmtlFor18mbps",
+            "Pmtl parameter for 18 Mbs data mode",
+            type = Types.Double,
+            default = "0.3722",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pmtlfor18mbps)
+
+        attr_pmtlfor12mbps = Attribute("pmtlFor12mbps",
+            "Pmtl parameter for 12 Mbs data mode",
+            type = Types.Double,
+            default = "0.2868",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pmtlfor12mbps)
+
+        attr_pmtlfor9mbps = Attribute("pmtlFor9mbps",
+            "Pmtl parameter for 9 Mbs data mode",
+            type = Types.Double,
+            default = "0.3932",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pmtlfor9mbps)
+
+        attr_islowlatency = Attribute("IsLowLatency",
+            "If true, we attempt to modelize a so-called low-latency device: a device where decisions about tx parameters can be made on a per-packet basis and feedback about the transmission of each packet is obtained before sending the next. Otherwise, we modelize a  high-latency device, that is a device where we cannot update our decision about tx parameters after every packet transmission.",
+            type = Types.Bool,
+            default = "True",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_islowlatency)
+
+        attr_maxssrc = Attribute("MaxSsrc",
+            "The maximum number of retransmission attempts for an RTS. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxssrc)
+
+        attr_maxslrc = Attribute("MaxSlrc",
+            "The maximum number of retransmission attempts for a DATA packet. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxslrc)
+
+        attr_rtsctsthreshold = Attribute("RtsCtsThreshold",
+            "If  the size of the data packet + LLC header + MAC header + FCS trailer is bigger than this value, we use an RTS/CTS handshake before sending the data, as per IEEE Std. 802.11-2007, Section 9.2.6. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtsctsthreshold)
+
+        attr_fragmentationthreshold = Attribute("FragmentationThreshold",
+            "If the size of the data packet + LLC header + MAC header + FCS trailer is biggerthan this value, we fragment it such that the size of the fragments are equal or smaller than this value, as per IEEE Std. 802.11-2007, Section 9.4. This value will not have any effect on some rate control algorithms.",
+            type = Types.Integer,
+            default = "2346",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_fragmentationthreshold)
+
+        attr_nonunicastmode = Attribute("NonUnicastMode",
+            "Wifi mode used for non-unicast transmissions.",
+            type = Types.String,
+            default = "Invalid-WifiMode",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_nonunicastmode)
+
+        attr_defaulttxpowerlevel = Attribute("DefaultTxPowerLevel",
+            "Default power level to be used for transmissions. This is the power level that is used by all those WifiManagers that do notimplement TX power control.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_defaulttxpowerlevel)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactxrtsfailed = Trace("MacTxRtsFailed", "The transmission of a RTS by the MAC layer has failed")
+
+        cls._register_trace(mactxrtsfailed)
+
+        mactxdatafailed = Trace("MacTxDataFailed", "The transmission of a data packet by the MAC layer has failed")
+
+        cls._register_trace(mactxdatafailed)
+
+        mactxfinalrtsfailed = Trace("MacTxFinalRtsFailed", "The transmission of a RTS has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinalrtsfailed)
+
+        mactxfinaldatafailed = Trace("MacTxFinalDataFailed", "The transmission of a data packet has exceeded the maximum number of attempts")
+
+        cls._register_trace(mactxfinaldatafailed)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3RraaWifiManager, self).__init__(ec, guid)
+        self._home = "ns3-rraa-wifi-manager-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/simple_channel.py b/src/nepi/resources/ns3/classes/simple_channel.py
new file mode 100644 (file)
index 0000000..37a9c42
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3SimpleChannel(NS3BaseChannel):
+    _rtype = "ns3::SimpleChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3SimpleChannel, self).__init__(ec, guid)
+        self._home = "ns3-simple-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/simple_net_device.py b/src/nepi/resources/ns3/classes/simple_net_device.py
new file mode 100644 (file)
index 0000000..293394a
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3SimpleNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::SimpleNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        pass
+
+    @classmethod
+    def _register_traces(cls):
+        
+        phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception")
+
+        cls._register_trace(phyrxdrop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3SimpleNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-simple-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/single_model_spectrum_channel.py b/src/nepi/resources/ns3/classes/single_model_spectrum_channel.py
new file mode 100644 (file)
index 0000000..3328562
--- /dev/null
@@ -0,0 +1,65 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3SingleModelSpectrumChannel(NS3BaseChannel):
+    _rtype = "ns3::SingleModelSpectrumChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_maxlossdb = Attribute("MaxLossDb",
+            "If a single-frequency PropagationLossModel is used, this value represents the maximum loss in dB for which transmissions will be passed to the receiving PHY. Signals for which the PropagationLossModel returns a loss bigger than this value will not be propagated to the receiver. This parameter is to be used to reduce the computational load by not propagating signals that are far beyond the interference range. Note that the default value corresponds to considering all signals for reception. Tune this value with care. ",
+            type = Types.Double,
+            default = "1e+09",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxlossdb)
+
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        pathloss = Trace("PathLoss", "This trace is fired whenever a new path loss value is calculated. The first and second parameters to the trace are pointers respectively to the TX and RX SpectrumPhy instances, whereas the third parameters is the loss value in dB. Note that the loss value reported by this trace is the single-frequency loss value obtained by evaluating only the TX and RX AntennaModels and the PropagationLossModel. In particular, note that SpectrumPropagationLossModel (even if present) is never used to evaluate the loss value reported in this trace. ")
+
+        cls._register_trace(pathloss)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3SingleModelSpectrumChannel, self).__init__(ec, guid)
+        self._home = "ns3-single-model-spectrum-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/sta_wifi_mac.py b/src/nepi/resources/ns3/classes/sta_wifi_mac.py
new file mode 100644 (file)
index 0000000..3b2288f
--- /dev/null
@@ -0,0 +1,247 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
+
+@clsinit_copy
+class NS3StaWifiMac(NS3BaseWifiMac):
+    _rtype = "ns3::StaWifiMac"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_proberequesttimeout = Attribute("ProbeRequestTimeout",
+            "The interval between two consecutive probe request attempts.",
+            type = Types.String,
+            default = "+50000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_proberequesttimeout)
+
+        attr_assocrequesttimeout = Attribute("AssocRequestTimeout",
+            "The interval between two consecutive assoc request attempts.",
+            type = Types.String,
+            default = "+500000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_assocrequesttimeout)
+
+        attr_maxmissedbeacons = Attribute("MaxMissedBeacons",
+            "Number of beacons which much be consecutively missed before we attempt to restart association.",
+            type = Types.Integer,
+            default = "10",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxmissedbeacons)
+
+        attr_qossupported = Attribute("QosSupported",
+            "This Boolean attribute is set to enable 802.11e/WMM-style QoS support at this STA",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_qossupported)
+
+        attr_htsupported = Attribute("HtSupported",
+            "This Boolean attribute is set to enable 802.11n support at this STA",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_htsupported)
+
+        attr_ctstoselfsupported = Attribute("CtsToSelfSupported",
+            "Use CTS to Self when using a rate that is not in the basic set rate",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ctstoselfsupported)
+
+        attr_ctstimeout = Attribute("CtsTimeout",
+            "When this timeout expires, the RTS/CTS handshake has failed.",
+            type = Types.String,
+            default = "+75000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ctstimeout)
+
+        attr_acktimeout = Attribute("AckTimeout",
+            "When this timeout expires, the DATA/ACK handshake has failed.",
+            type = Types.String,
+            default = "+75000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_acktimeout)
+
+        attr_basicblockacktimeout = Attribute("BasicBlockAckTimeout",
+            "When this timeout expires, the BASIC_BLOCK_ACK_REQ/BASIC_BLOCK_ACK handshake has failed.",
+            type = Types.String,
+            default = "+281000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_basicblockacktimeout)
+
+        attr_compressedblockacktimeout = Attribute("CompressedBlockAckTimeout",
+            "When this timeout expires, the COMPRESSED_BLOCK_ACK_REQ/COMPRESSED_BLOCK_ACK handshake has failed.",
+            type = Types.String,
+            default = "+107000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_compressedblockacktimeout)
+
+        attr_sifs = Attribute("Sifs",
+            "The value of the SIFS constant.",
+            type = Types.String,
+            default = "+16000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_sifs)
+
+        attr_eifsnodifs = Attribute("EifsNoDifs",
+            "The value of EIFS-DIFS",
+            type = Types.String,
+            default = "+60000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_eifsnodifs)
+
+        attr_slot = Attribute("Slot",
+            "The duration of a Slot.",
+            type = Types.String,
+            default = "+9000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_slot)
+
+        attr_pifs = Attribute("Pifs",
+            "The value of the PIFS constant.",
+            type = Types.String,
+            default = "+25000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_pifs)
+
+        attr_rifs = Attribute("Rifs",
+            "The value of the RIFS constant.",
+            type = Types.String,
+            default = "+2000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rifs)
+
+        attr_maxpropagationdelay = Attribute("MaxPropagationDelay",
+            "The maximum propagation delay. Unused for now.",
+            type = Types.String,
+            default = "+3333.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpropagationdelay)
+
+        attr_ssid = Attribute("Ssid",
+            "The ssid we want to belong to.",
+            type = Types.String,
+            default = "default",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ssid)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        assoc = Trace("Assoc", "Associated with an access point.")
+
+        cls._register_trace(assoc)
+
+        deassoc = Trace("DeAssoc", "Association with an access point lost.")
+
+        cls._register_trace(deassoc)
+
+        txokheader = Trace("TxOkHeader", "The header of successfully transmitted packet")
+
+        cls._register_trace(txokheader)
+
+        txerrheader = Trace("TxErrHeader", "The header of unsuccessfully transmitted packet")
+
+        cls._register_trace(txerrheader)
+
+        mactx = Trace("MacTx", "A packet has been received from higher layers and is being processed in preparation for queueing for transmission.")
+
+        cls._register_trace(mactx)
+
+        mactxdrop = Trace("MacTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.")
+
+        cls._register_trace(mactxdrop)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+        macrxdrop = Trace("MacRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.")
+
+        cls._register_trace(macrxdrop)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3StaWifiMac, self).__init__(ec, guid)
+        self._home = "ns3-sta-wifi-mac-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.py b/src/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.py
new file mode 100644 (file)
index 0000000..65b99b6
--- /dev/null
@@ -0,0 +1,155 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3SteadyStateRandomWaypointMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::SteadyStateRandomWaypointMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_minspeed = Attribute("MinSpeed",
+            "Minimum speed value, [m/s]",
+            type = Types.Double,
+            default = "0.3",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_minspeed)
+
+        attr_maxspeed = Attribute("MaxSpeed",
+            "Maximum speed value, [m/s]",
+            type = Types.Double,
+            default = "0.7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxspeed)
+
+        attr_minpause = Attribute("MinPause",
+            "Minimum pause value, [s]",
+            type = Types.Double,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_minpause)
+
+        attr_maxpause = Attribute("MaxPause",
+            "Maximum pause value, [s]",
+            type = Types.Double,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpause)
+
+        attr_minx = Attribute("MinX",
+            "Minimum X value of traveling region, [m]",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_minx)
+
+        attr_maxx = Attribute("MaxX",
+            "Maximum X value of traveling region, [m]",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxx)
+
+        attr_miny = Attribute("MinY",
+            "Minimum Y value of traveling region, [m]",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_miny)
+
+        attr_maxy = Attribute("MaxY",
+            "Maximum Y value of traveling region, [m]",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxy)
+
+        attr_z = Attribute("Z",
+            "Z value of traveling region (fixed), [m]",
+            type = Types.Double,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_z)
+
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3SteadyStateRandomWaypointMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-steady-state-random-waypoint-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/subscriber_station_net_device.py b/src/nepi/resources/ns3/classes/subscriber_station_net_device.py
new file mode 100644 (file)
index 0000000..18441c2
--- /dev/null
@@ -0,0 +1,215 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3SubscriberStationNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::SubscriberStationNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_lostdlmapinterval = Attribute("LostDlMapInterval",
+            "Time since last received DL-MAP message before downlink synchronization is considered lost. Maximum is 600ms",
+            type = Types.String,
+            default = "+500000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_lostdlmapinterval)
+
+        attr_lostulmapinterval = Attribute("LostUlMapInterval",
+            "Time since last received UL-MAP before uplink synchronization is considered lost, maximum is 600.",
+            type = Types.String,
+            default = "+500000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_lostulmapinterval)
+
+        attr_maxdcdinterval = Attribute("MaxDcdInterval",
+            "Maximum time between transmission of DCD messages. Maximum is 10s",
+            type = Types.String,
+            default = "+10000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxdcdinterval)
+
+        attr_maxucdinterval = Attribute("MaxUcdInterval",
+            "Maximum time between transmission of UCD messages. Maximum is 10s",
+            type = Types.String,
+            default = "+10000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxucdinterval)
+
+        attr_intervalt1 = Attribute("IntervalT1",
+            "Wait for DCD timeout. Maximum is 5*maxDcdInterval",
+            type = Types.String,
+            default = "+50000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_intervalt1)
+
+        attr_intervalt2 = Attribute("IntervalT2",
+            "Wait for broadcast ranging timeout, i.e., wait for initial ranging opportunity. Maximum is 5*Ranging interval",
+            type = Types.String,
+            default = "+10000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_intervalt2)
+
+        attr_intervalt3 = Attribute("IntervalT3",
+            "ranging Response reception timeout following the transmission of a ranging request. Maximum is 200ms",
+            type = Types.String,
+            default = "+200000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_intervalt3)
+
+        attr_intervalt7 = Attribute("IntervalT7",
+            "wait for DSA/DSC/DSD Response timeout. Maximum is 1s",
+            type = Types.String,
+            default = "+100000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_intervalt7)
+
+        attr_intervalt12 = Attribute("IntervalT12",
+            "Wait for UCD descriptor.Maximum is 5*MaxUcdInterval",
+            type = Types.String,
+            default = "+10000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_intervalt12)
+
+        attr_intervalt20 = Attribute("IntervalT20",
+            "Time the SS searches for preambles on a given channel. Minimum is 2 MAC frames",
+            type = Types.String,
+            default = "+500000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_intervalt20)
+
+        attr_intervalt21 = Attribute("IntervalT21",
+            "time the SS searches for (decodable) DL-MAP on a given channel",
+            type = Types.String,
+            default = "+10000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_intervalt21)
+
+        attr_maxcontentionrangingretries = Attribute("MaxContentionRangingRetries",
+            "Number of retries on contention Ranging Requests",
+            type = Types.Integer,
+            default = "16",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxcontentionrangingretries)
+
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "1400",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+        attr_rtg = Attribute("RTG",
+            "receive/transmit transition gap.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rtg)
+
+        attr_ttg = Attribute("TTG",
+            "transmit/receive transition gap.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ttg)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        sstxdrop = Trace("SSTxDrop", "A packet has been dropped in the MAC layer before being queued for transmission.")
+
+        cls._register_trace(sstxdrop)
+
+        sspromiscrx = Trace("SSPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(sspromiscrx)
+
+        ssrx = Trace("SSRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(ssrx)
+
+        ssrxdrop = Trace("SSRxDrop", "A packet has been dropped in the MAC layer after it has been passed up from the physical layer.")
+
+        cls._register_trace(ssrxdrop)
+
+        rx = Trace("Rx", "Receive trace")
+
+        cls._register_trace(rx)
+
+        tx = Trace("Tx", "Transmit trace")
+
+        cls._register_trace(tx)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3SubscriberStationNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-subscriber-station-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/tap_bridge.py b/src/nepi/resources/ns3/classes/tap_bridge.py
new file mode 100644 (file)
index 0000000..8438d28
--- /dev/null
@@ -0,0 +1,120 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3TapBridge(NS3BaseNetDevice):
+    _rtype = "ns3::TapBridge"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+        attr_devicename = Attribute("DeviceName",
+            "The name of the tap device to create.",
+            type = Types.String,
+            default = "",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_devicename)
+
+        attr_gateway = Attribute("Gateway",
+            "The IP address of the default gateway to assign to the host machine, when in ConfigureLocal mode.",
+            type = Types.String,
+            default = "255.255.255.255",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_gateway)
+
+        attr_ipaddress = Attribute("IpAddress",
+            "The IP address to assign to the tap device, when in ConfigureLocal mode.  This address will override the discovered IP address of the simulated device.",
+            type = Types.String,
+            default = "255.255.255.255",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ipaddress)
+
+        attr_macaddress = Attribute("MacAddress",
+            "The MAC address to assign to the tap device, when in ConfigureLocal mode.  This address will override the discovered MAC address of the simulated device.",
+            type = Types.String,
+            default = "ff:ff:ff:ff:ff:ff",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_macaddress)
+
+        attr_netmask = Attribute("Netmask",
+            "The network mask to assign to the tap device, when in ConfigureLocal mode.  This address will override the discovered MAC address of the simulated device.",
+            type = Types.String,
+            default = "255.255.255.255",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_netmask)
+
+        attr_start = Attribute("Start",
+            "The simulation time at which to spin up the tap device read thread.",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_start)
+
+        attr_stop = Attribute("Stop",
+            "The simulation time at which to tear down the tap device read thread.",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stop)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3TapBridge, self).__init__(ec, guid)
+        self._home = "ns3-tap-bridge-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/tcp_l4protocol.py b/src/nepi/resources/ns3/classes/tcp_l4protocol.py
new file mode 100644 (file)
index 0000000..ef21f8f
--- /dev/null
@@ -0,0 +1,70 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3TcpL4Protocol(NS3Base):
+    _rtype = "ns3::TcpL4Protocol"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_rttestimatortype = Attribute("RttEstimatorType",
+            "Type of RttEstimator objects.",
+            type = Types.String,
+            default = "ns3::RttMeanDeviation",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rttestimatortype)
+
+        attr_sockettype = Attribute("SocketType",
+            "Socket type of TCP objects.",
+            type = Types.String,
+            default = "ns3::TcpNewReno",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_sockettype)
+
+        attr_protocolnumber = Attribute("ProtocolNumber",
+            "The Ip protocol number.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_protocolnumber)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3TcpL4Protocol, self).__init__(ec, guid)
+        self._home = "ns3-tcp-l4protocol-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.py b/src/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..620d904
--- /dev/null
@@ -0,0 +1,110 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3ThreeLogDistancePropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::ThreeLogDistancePropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_distance0 = Attribute("Distance0",
+            "Beginning of the first (near) distance field",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_distance0)
+
+        attr_distance1 = Attribute("Distance1",
+            "Beginning of the second (middle) distance field.",
+            type = Types.Double,
+            default = "200",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_distance1)
+
+        attr_distance2 = Attribute("Distance2",
+            "Beginning of the third (far) distance field.",
+            type = Types.Double,
+            default = "500",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_distance2)
+
+        attr_exponent0 = Attribute("Exponent0",
+            "The exponent for the first field.",
+            type = Types.Double,
+            default = "1.9",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_exponent0)
+
+        attr_exponent1 = Attribute("Exponent1",
+            "The exponent for the second field.",
+            type = Types.Double,
+            default = "3.8",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_exponent1)
+
+        attr_exponent2 = Attribute("Exponent2",
+            "The exponent for the third field.",
+            type = Types.Double,
+            default = "3.8",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_exponent2)
+
+        attr_referenceloss = Attribute("ReferenceLoss",
+            "The reference loss at distance d0 (dB). (Default is Friis at 1m with 5.15 GHz)",
+            type = Types.Double,
+            default = "46.6777",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_referenceloss)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3ThreeLogDistancePropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-three-log-distance-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.py b/src/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.py
new file mode 100644 (file)
index 0000000..0dfadb8
--- /dev/null
@@ -0,0 +1,80 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+class NS3TwoRayGroundPropagationLossModel(NS3BasePropagationLossModel):
+    _rtype = "ns3::TwoRayGroundPropagationLossModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_frequency = Attribute("Frequency",
+            "The carrier frequency (in Hz) at which propagation occurs  (default is 5.15 GHz).",
+            type = Types.Double,
+            default = "5.15e+09",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_frequency)
+
+        attr_systemloss = Attribute("SystemLoss",
+            "The system loss",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_systemloss)
+
+        attr_mindistance = Attribute("MinDistance",
+            "The distance under which the propagation model refuses to give results (m)",
+            type = Types.Double,
+            default = "0.5",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mindistance)
+
+        attr_heightabovez = Attribute("HeightAboveZ",
+            "The height of the antenna (m) above the node\'s Z coordinate",
+            type = Types.Double,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_heightabovez)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3TwoRayGroundPropagationLossModel, self).__init__(ec, guid)
+        self._home = "ns3-two-ray-ground-propagation-loss-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/uan_channel.py b/src/nepi/resources/ns3/classes/uan_channel.py
new file mode 100644 (file)
index 0000000..4683b78
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3UanChannel(NS3BaseChannel):
+    _rtype = "ns3::UanChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3UanChannel, self).__init__(ec, guid)
+        self._home = "ns3-uan-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/udp_client.py b/src/nepi/resources/ns3/classes/udp_client.py
new file mode 100644 (file)
index 0000000..e242eb6
--- /dev/null
@@ -0,0 +1,110 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3UdpClient(NS3BaseApplication):
+    _rtype = "ns3::UdpClient"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_maxpackets = Attribute("MaxPackets",
+            "The maximum number of packets the application will send",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpackets)
+
+        attr_interval = Attribute("Interval",
+            "The time to wait between packets",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_interval)
+
+        attr_remoteaddress = Attribute("RemoteAddress",
+            "The destination Address of the outbound packets",
+            type = Types.String,
+            default = "00-00-00",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remoteaddress)
+
+        attr_remoteport = Attribute("RemotePort",
+            "The destination port of the outbound packets",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remoteport)
+
+        attr_packetsize = Attribute("PacketSize",
+            "Size of packets generated. The minimum packet size is 12 bytes which is the size of the header carrying the sequence number and the time stamp.",
+            type = Types.Integer,
+            default = "1024",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_packetsize)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3UdpClient, self).__init__(ec, guid)
+        self._home = "ns3-udp-client-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/udp_echo_client.py b/src/nepi/resources/ns3/classes/udp_echo_client.py
new file mode 100644 (file)
index 0000000..9293b07
--- /dev/null
@@ -0,0 +1,115 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3UdpEchoClient(NS3BaseApplication):
+    _rtype = "ns3::UdpEchoClient"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_maxpackets = Attribute("MaxPackets",
+            "The maximum number of packets the application will send",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpackets)
+
+        attr_interval = Attribute("Interval",
+            "The time to wait between packets",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_interval)
+
+        attr_remoteaddress = Attribute("RemoteAddress",
+            "The destination Address of the outbound packets",
+            type = Types.String,
+            default = "00-00-00",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remoteaddress)
+
+        attr_remoteport = Attribute("RemotePort",
+            "The destination port of the outbound packets",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remoteport)
+
+        attr_packetsize = Attribute("PacketSize",
+            "Size of echo data in outbound packets",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_packetsize)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        tx = Trace("Tx", "A new packet is created and is sent")
+
+        cls._register_trace(tx)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3UdpEchoClient, self).__init__(ec, guid)
+        self._home = "ns3-udp-echo-client-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/udp_echo_server.py b/src/nepi/resources/ns3/classes/udp_echo_server.py
new file mode 100644 (file)
index 0000000..cd73643
--- /dev/null
@@ -0,0 +1,70 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3UdpEchoServer(NS3BaseApplication):
+    _rtype = "ns3::UdpEchoServer"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_port = Attribute("Port",
+            "Port on which we listen for incoming packets.",
+            type = Types.Integer,
+            default = "9",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_port)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3UdpEchoServer, self).__init__(ec, guid)
+        self._home = "ns3-udp-echo-server-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/udp_l4protocol.py b/src/nepi/resources/ns3/classes/udp_l4protocol.py
new file mode 100644 (file)
index 0000000..c81c162
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3UdpL4Protocol(NS3Base):
+    _rtype = "ns3::UdpL4Protocol"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_protocolnumber = Attribute("ProtocolNumber",
+            "The Ip protocol number.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_protocolnumber)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3UdpL4Protocol, self).__init__(ec, guid)
+        self._home = "ns3-udp-l4protocol-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/udp_server.py b/src/nepi/resources/ns3/classes/udp_server.py
new file mode 100644 (file)
index 0000000..86b109b
--- /dev/null
@@ -0,0 +1,80 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3UdpServer(NS3BaseApplication):
+    _rtype = "ns3::UdpServer"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_port = Attribute("Port",
+            "Port on which we listen for incoming packets.",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_port)
+
+        attr_packetwindowsize = Attribute("PacketWindowSize",
+            "The size of the window used to compute the packet loss. This value should be a multiple of 8.",
+            type = Types.Integer,
+            default = "32",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_packetwindowsize)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3UdpServer, self).__init__(ec, guid)
+        self._home = "ns3-udp-server-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/udp_trace_client.py b/src/nepi/resources/ns3/classes/udp_trace_client.py
new file mode 100644 (file)
index 0000000..6263666
--- /dev/null
@@ -0,0 +1,90 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3UdpTraceClient(NS3BaseApplication):
+    _rtype = "ns3::UdpTraceClient"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_remoteaddress = Attribute("RemoteAddress",
+            "The destination Address of the outbound packets",
+            type = Types.String,
+            default = "00-00-00",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remoteaddress)
+
+        attr_remoteport = Attribute("RemotePort",
+            "The destination port of the outbound packets",
+            type = Types.Integer,
+            default = "100",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remoteport)
+
+        attr_maxpacketsize = Attribute("MaxPacketSize",
+            "The maximum size of a packet.",
+            type = Types.Integer,
+            default = "1024",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_maxpacketsize)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3UdpTraceClient, self).__init__(ec, guid)
+        self._home = "ns3-udp-trace-client-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/v4ping.py b/src/nepi/resources/ns3/classes/v4ping.py
new file mode 100644 (file)
index 0000000..c9a0958
--- /dev/null
@@ -0,0 +1,105 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+class NS3V4Ping(NS3BaseApplication):
+    _rtype = "ns3::V4Ping"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_remote = Attribute("Remote",
+            "The address of the machine we want to ping.",
+            type = Types.String,
+            default = "102.102.102.102",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_remote)
+
+        attr_verbose = Attribute("Verbose",
+            "Produce usual output.",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_verbose)
+
+        attr_interval = Attribute("Interval",
+            "Wait  interval  seconds between sending each packet.",
+            type = Types.String,
+            default = "+1000000000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_interval)
+
+        attr_size = Attribute("Size",
+            "The number of data bytes to be sent, real packet will be 8 (ICMP) + 20 (IP) bytes longer.",
+            type = Types.Integer,
+            default = "56",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_size)
+
+        attr_starttime = Attribute("StartTime",
+            "Time at which the application will start",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_starttime)
+
+        attr_stoptime = Attribute("StopTime",
+            "Time at which the application will stop",
+            type = Types.String,
+            default = "+0.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stoptime)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        rtt = Trace("Rtt", "The rtt calculated by the ping.")
+
+        cls._register_trace(rtt)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3V4Ping, self).__init__(ec, guid)
+        self._home = "ns3-v4ping-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/virtual_net_device.py b/src/nepi/resources/ns3/classes/virtual_net_device.py
new file mode 100644 (file)
index 0000000..a57f363
--- /dev/null
@@ -0,0 +1,71 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3VirtualNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::VirtualNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "1500",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        mactx = Trace("MacTx", "Trace source indicating a packet has arrived for transmission by this device")
+
+        cls._register_trace(mactx)
+
+        macpromiscrx = Trace("MacPromiscRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a promiscuous trace,")
+
+        cls._register_trace(macpromiscrx)
+
+        macrx = Trace("MacRx", "A packet has been received by this device, has been passed up from the physical layer and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,")
+
+        cls._register_trace(macrx)
+
+        sniffer = Trace("Sniffer", "Trace source simulating a non-promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(sniffer)
+
+        promiscsniffer = Trace("PromiscSniffer", "Trace source simulating a promiscuous packet sniffer attached to the device")
+
+        cls._register_trace(promiscsniffer)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3VirtualNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-virtual-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/waypoint_mobility_model.py b/src/nepi/resources/ns3/classes/waypoint_mobility_model.py
new file mode 100644 (file)
index 0000000..116ab45
--- /dev/null
@@ -0,0 +1,95 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+class NS3WaypointMobilityModel(NS3BaseMobilityModel):
+    _rtype = "ns3::WaypointMobilityModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_waypointsleft = Attribute("WaypointsLeft",
+            "The number of waypoints remaining.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_waypointsleft)
+
+        attr_lazynotify = Attribute("LazyNotify",
+            "Only call NotifyCourseChange when position is calculated.",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_lazynotify)
+
+        attr_initialpositioniswaypoint = Attribute("InitialPositionIsWaypoint",
+            "Calling SetPosition with no waypoints creates a waypoint.",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_initialpositioniswaypoint)
+
+        attr_position = Attribute("Position",
+            "The current position of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved)
+
+        cls._register_attribute(attr_position)
+
+        attr_velocity = Attribute("Velocity",
+            "The current velocity of the mobility model.",
+            type = Types.String,
+            default = "0:0:0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_velocity)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        coursechange = Trace("CourseChange", "The value of the position and/or velocity vector changed")
+
+        cls._register_trace(coursechange)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3WaypointMobilityModel, self).__init__(ec, guid)
+        self._home = "ns3-waypoint-mobility-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/wifi_net_device.py b/src/nepi/resources/ns3/classes/wifi_net_device.py
new file mode 100644 (file)
index 0000000..f4f7345
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+class NS3WifiNetDevice(NS3BaseNetDevice):
+    _rtype = "ns3::WifiNetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_mtu = Attribute("Mtu",
+            "The MAC-level Maximum Transmission Unit",
+            type = Types.Integer,
+            default = "2296",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_mtu)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3WifiNetDevice, self).__init__(ec, guid)
+        self._home = "ns3-wifi-net-device-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/yans_error_rate_model.py b/src/nepi/resources/ns3/classes/yans_error_rate_model.py
new file mode 100644 (file)
index 0000000..0e119dd
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3errorratemodel import NS3BaseErrorRateModel 
+
+@clsinit_copy
+class NS3YansErrorRateModel(NS3BaseErrorRateModel):
+    _rtype = "ns3::YansErrorRateModel"
+
+    @classmethod
+    def _register_attributes(cls):
+        pass
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3YansErrorRateModel, self).__init__(ec, guid)
+        self._home = "ns3-yans-error-rate-model-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/yans_wifi_channel.py b/src/nepi/resources/ns3/classes/yans_wifi_channel.py
new file mode 100644 (file)
index 0000000..325c29b
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+class NS3YansWifiChannel(NS3BaseChannel):
+    _rtype = "ns3::YansWifiChannel"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_id = Attribute("Id",
+            "The id (unique integer) of this Channel.",
+            type = Types.Integer,
+            default = "0",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.NoWrite)
+
+        cls._register_attribute(attr_id)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        pass
+
+    def __init__(self, ec, guid):
+        super(NS3YansWifiChannel, self).__init__(ec, guid)
+        self._home = "ns3-yans-wifi-channel-%s" % self.guid
diff --git a/src/nepi/resources/ns3/classes/yans_wifi_phy.py b/src/nepi/resources/ns3/classes/yans_wifi_phy.py
new file mode 100644 (file)
index 0000000..2c6ad1c
--- /dev/null
@@ -0,0 +1,253 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3wifiphy import NS3BaseWifiPhy 
+
+@clsinit_copy
+class NS3YansWifiPhy(NS3BaseWifiPhy):
+    _rtype = "ns3::YansWifiPhy"
+
+    @classmethod
+    def _register_attributes(cls):
+        
+        attr_energydetectionthreshold = Attribute("EnergyDetectionThreshold",
+            "The energy of a received signal should be higher than this threshold (dbm) to allow the PHY layer to detect the signal.",
+            type = Types.Double,
+            default = "-96",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_energydetectionthreshold)
+
+        attr_ccamode1threshold = Attribute("CcaMode1Threshold",
+            "The energy of a received signal should be higher than this threshold (dbm) to allow the PHY layer to declare CCA BUSY state",
+            type = Types.Double,
+            default = "-99",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ccamode1threshold)
+
+        attr_txgain = Attribute("TxGain",
+            "Transmission gain (dB).",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_txgain)
+
+        attr_rxgain = Attribute("RxGain",
+            "Reception gain (dB).",
+            type = Types.Double,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rxgain)
+
+        attr_txpowerlevels = Attribute("TxPowerLevels",
+            "Number of transmission power levels available between TxPowerStart and TxPowerEnd included.",
+            type = Types.Integer,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_txpowerlevels)
+
+        attr_txpowerend = Attribute("TxPowerEnd",
+            "Maximum available transmission level (dbm).",
+            type = Types.Double,
+            default = "16.0206",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_txpowerend)
+
+        attr_txpowerstart = Attribute("TxPowerStart",
+            "Minimum available transmission level (dbm).",
+            type = Types.Double,
+            default = "16.0206",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_txpowerstart)
+
+        attr_rxnoisefigure = Attribute("RxNoiseFigure",
+            "Loss (dB) in the Signal-to-Noise-Ratio due to non-idealities in the receiver. According to Wikipedia (http://en.wikipedia.org/wiki/Noise_figure), this is \"the difference in decibels (dB) between the noise output of the actual receiver to the noise output of an  ideal receiver with the same overall gain and bandwidth when the receivers  are connected to sources at the standard noise temperature T0 (usually 290 K)\". For",
+            type = Types.Double,
+            default = "7",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_rxnoisefigure)
+
+        attr_channelswitchdelay = Attribute("ChannelSwitchDelay",
+            "Delay between two short frames transmitted on different frequencies.",
+            type = Types.String,
+            default = "+250000.0ns",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_channelswitchdelay)
+
+        attr_channelnumber = Attribute("ChannelNumber",
+            "Channel center frequency = Channel starting frequency + 5 MHz * nch",
+            type = Types.Integer,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_channelnumber)
+
+        attr_frequency = Attribute("Frequency",
+            "The operating frequency.",
+            type = Types.Integer,
+            default = "2407",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_frequency)
+
+        attr_transmitters = Attribute("Transmitters",
+            "The number of transmitters.",
+            type = Types.Integer,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_transmitters)
+
+        attr_recievers = Attribute("Recievers",
+            "The number of recievers.",
+            type = Types.Integer,
+            default = "1",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_recievers)
+
+        attr_shortguardenabled = Attribute("ShortGuardEnabled",
+            "Whether or not short guard interval is enabled.",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_shortguardenabled)
+
+        attr_ldpcenabled = Attribute("LdpcEnabled",
+            "Whether or not LDPC is enabled.",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_ldpcenabled)
+
+        attr_stbcenabled = Attribute("STBCEnabled",
+            "Whether or not STBC is enabled.",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_stbcenabled)
+
+        attr_greenfieldenabled = Attribute("GreenfieldEnabled",
+            "Whether or not STBC is enabled.",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_greenfieldenabled)
+
+        attr_channelbonding = Attribute("ChannelBonding",
+            "Whether 20MHz or 40MHz.",
+            type = Types.Bool,
+            default = "False",  
+            allowed = None,
+            range = None,    
+            flags = Flags.Reserved | Flags.Construct)
+
+        cls._register_attribute(attr_channelbonding)
+
+
+
+    @classmethod
+    def _register_traces(cls):
+        
+        phytxbegin = Trace("PhyTxBegin", "Trace source indicating a packet has begun transmitting over the channel medium")
+
+        cls._register_trace(phytxbegin)
+
+        phytxend = Trace("PhyTxEnd", "Trace source indicating a packet has been completely transmitted over the channel. NOTE: the only official WifiPhy implementation available to this date (YansWifiPhy) never fires this trace source.")
+
+        cls._register_trace(phytxend)
+
+        phytxdrop = Trace("PhyTxDrop", "Trace source indicating a packet has been dropped by the device during transmission")
+
+        cls._register_trace(phytxdrop)
+
+        phyrxbegin = Trace("PhyRxBegin", "Trace source indicating a packet has begun being received from the channel medium by the device")
+
+        cls._register_trace(phyrxbegin)
+
+        phyrxend = Trace("PhyRxEnd", "Trace source indicating a packet has been completely received from the channel medium by the device")
+
+        cls._register_trace(phyrxend)
+
+        phyrxdrop = Trace("PhyRxDrop", "Trace source indicating a packet has been dropped by the device during reception")
+
+        cls._register_trace(phyrxdrop)
+
+        monitorsnifferrx = Trace("MonitorSnifferRx", "Trace source simulating a wifi device in monitor mode sniffing all received frames")
+
+        cls._register_trace(monitorsnifferrx)
+
+        monitorsniffertx = Trace("MonitorSnifferTx", "Trace source simulating the capability of a wifi device in monitor mode to sniff all frames being transmitted")
+
+        cls._register_trace(monitorsniffertx)
+
+
+
+    def __init__(self, ec, guid):
+        super(NS3YansWifiPhy, self).__init__(ec, guid)
+        self._home = "ns3-yans-wifi-phy-%s" % self.guid
diff --git a/src/nepi/resources/ns3/ns3application.py b/src/nepi/resources/ns3/ns3application.py
new file mode 100644 (file)
index 0000000..302e128
--- /dev/null
@@ -0,0 +1,76 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy, ResourceState, \
+        reschedule_delay
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseApplication(NS3Base):
+    _rtype = "abstract::ns3::Application"
+
+    @property
+    def node(self):
+        from nepi.resources.ns3.ns3node import NS3BaseNode
+        nodes = self.get_connected(NS3BaseNode.get_rtype())
+
+        if not nodes: 
+            msg = "Application not connected to node"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return nodes[0]
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.node)
+        return rms
+
+    def _connect_object(self):
+        node = self.node
+        if node.uuid not in self.connected:
+            self.simulation.invoke(node.uuid, "AddApplication", self.uuid)
+            self._connected.add(node.uuid)
+
+    def do_stop(self):
+        if self.state == ResourceState.STARTED:
+            # No need to do anything, simulation.Destroy() will stop every object
+            self.info("Stopping command '%s'" % command)
+            self.simulation.invoke(self.uuid, "Stop")
+            self.set_stopped()
+
+    def do_start(self):
+        if self.simulation.state < ResourceState.STARTED:
+            self.debug("---- RESCHEDULING START ----" )
+            self.ec.schedule(reschedule_delay, self.start)
+        else:
+            super(NS3BaseApplication, self).do_start()
+            self._start_time = self.simulation.start_time
+
+    @property
+    def state(self):
+        if self._state == ResourceState.STARTED:
+            is_running = self.simulation.invoke(self.uuid, "isAppRunning")
+            
+            if not is_running:
+                self.set_stopped()
+
+        return self._state
+
diff --git a/src/nepi/resources/ns3/ns3arpl3protocol.py b/src/nepi/resources/ns3/ns3arpl3protocol.py
new file mode 100644 (file)
index 0000000..b40c581
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseArpL3Protocol(NS3Base):
+    _rtype = "abstract::ns3::ArpL3Protocol"
+
+    @property
+    def node(self):
+        from nepi.resources.ns3.ns3node import NS3BaseNode
+        nodes = self.get_connected(NS3BaseNode.get_rtype())
+
+        if not nodes: 
+            msg = "ArpL3Protocol not connected to node"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return nodes[0]
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.node)
+        return rms
+
diff --git a/src/nepi/resources/ns3/ns3base.py b/src/nepi/resources/ns3/ns3base.py
new file mode 100644 (file)
index 0000000..8a06e4b
--- /dev/null
@@ -0,0 +1,167 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+from nepi.execution.attribute import Flags
+from nepi.execution.trace import TraceAttr
+
+@clsinit_copy
+class NS3Base(ResourceManager):
+    _rtype = "abstract::ns3::Object"
+    _backend_type = "ns3"
+
+    def __init__(self, ec, guid):
+        super(NS3Base, self).__init__(ec, guid)
+        self._uuid = None
+        self._connected = set()
+        self._trace_filename = dict()
+
+    @property
+    def connected(self):
+        return self._connected
+
+    @property
+    def uuid(self):
+        return self._uuid
+
+    @property
+    def simulation(self):
+        return self.node.simulation
+
+    @property
+    def node(self):
+        from nepi.resources.ns3.ns3node import NS3BaseNode
+        nodes = self.get_connected(NS3BaseNode.get_rtype())
+        if nodes: return nodes[0]
+        return None
+
+    def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0):
+        filename = self._trace_filename.get(name)
+        if not filename:
+            self.error("Can not resolve trace %s. Did you enabled it?" % name)
+            return ""
+
+        return self.simulation.trace(filename, attr, block, offset)
+
+    @property
+    def _rms_to_wait(self):
+        """ Returns the collection of ns-3 RMs that this RM needs to
+        wait for before start
+
+        This method should be overriden to wait for other ns-3
+        objects to be deployed before proceeding with the deployment
+
+        """
+        rms = set()
+        node = self.node
+        if node: rms.add(node)
+        return rms
+
+    def _instantiate_object(self):
+        if self.uuid:
+            return 
+
+        kwargs = dict()
+        for attr in self._attrs.values():
+            if not ( attr.has_flag(Flags.Construct) and attr.has_changed() ):
+                continue
+
+            kwargs[attr.name] = attr._value
+
+        self._uuid = self.simulation.factory(self.get_rtype(), **kwargs)
+
+    def _configure_object(self):
+        pass
+
+    def _connect_object(self):
+        node = self.node
+        if node and node.uuid not in self.connected:
+            self.simulation.invoke(node.uuid, "AggregateObject", self.uuid)
+            self._connected.add(node.uuid)
+
+    def _wait_rms(self):
+        """ Returns True if dependent RMs are not yer READY, False otherwise"""
+        for rm in self._rms_to_wait:
+            if rm and rm.state < ResourceState.READY:
+                return True
+        return False
+
+    def do_provision(self):
+        # TODO: create run dir for ns3 object !!!!
+        # self.simulation.node.mkdir(self.run_home)
+
+        self._instantiate_object()
+        self._connect_object()
+        self._configure_object()
+      
+        self.info("Provisioning finished")
+
+        super(NS3Base, self).do_provision()
+
+    def do_deploy(self):
+        if self._wait_rms():
+            self.debug("---- RESCHEDULING DEPLOY ----" )
+            self.ec.schedule(reschedule_delay, self.deploy)
+        else:
+            self.do_discover()
+            self.do_provision()
+
+            self.set_ready()
+
+    def do_start(self):
+        if self.state == ResourceState.READY:
+            # No need to do anything, simulation.Run() will start every object
+            self.info("Starting")
+            self.set_started()
+        else:
+            msg = " Failed "
+            self.error(msg, out, err)
+            raise RuntimeError, msg
+
+    def do_stop(self):
+        if self.state == ResourceState.STARTED:
+            # No need to do anything, simulation.Destroy() will stop every object
+            self.info("Stopping command '%s'" % command)
+            self.set_stopped()
+    
+    @property
+    def state(self):
+        return self._state
+
+    def get(self, name):
+        if self.state in [ResourceState.READY, ResourceState.STARTED] and \
+                self.has_flag(name, Flags.Reserved) and \
+                not self.has_flag(name, Flags.NoRead): 
+            return self.simulation.ns3_get(self.uuid, name)
+        else:
+            value = super(NS3Base, self).get(name)
+
+        return value
+
+    def set(self, name, value):
+        if self.state in [ResourceState.READY, ResourceState.STARTED] and \
+                self.has_flag(name, Flags.Reserved) and \
+                not (self.has_flag(Flags.NoWrite) or self.has_flag(name, Flags.Design)): 
+            self.simulation.ns3_set(self.uuid, name, value)
+        
+        value = super(NS3Base, self).set(name, value)
+
+        return value
+
diff --git a/src/nepi/resources/ns3/ns3channel.py b/src/nepi/resources/ns3/ns3channel.py
new file mode 100644 (file)
index 0000000..bdeec57
--- /dev/null
@@ -0,0 +1,51 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseChannel(NS3Base):
+    _rtype = "abstract::ns3::Channel"
+
+    @property
+    def simulation(self):
+        return self.devices[0].node.simulation
+
+    @property
+    def devices(self):
+        from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
+        devices = self.get_connected(NS3BaseNetDevice.get_rtype())
+
+        if not devices: 
+            msg = "Channel not connected to devices"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return devices
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.simulation)
+        return rms
+
+    def _connect_object(self):
+        pass
+
diff --git a/src/nepi/resources/ns3/ns3client.py b/src/nepi/resources/ns3/ns3client.py
new file mode 100644 (file)
index 0000000..4a9b48d
--- /dev/null
@@ -0,0 +1,51 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+class NS3Client(object):
+    """ Common Interface for NS3 client classes """
+    def __init__(self):
+        super(NS3Client, self).__init__()
+
+    def create(self, *args, **kwargs):
+        pass
+
+    def factory(self, *args, **kwargs):
+        pass
+
+    def invoke(self, *args, **kwargs):
+        pass
+
+    def set(self, *args, **kwargs):
+        pass
+
+    def get(self, *args, **kwargs):
+        pass
+
+    def flush(self, *args, **kwargs):
+        pass
+
+    def start(self, *args, **kwargs):
+        pass
+
+    def stop(self, *args, **kwargs):
+        pass
+
+    def shutdown(self, *args, **kwargs):
+        pass
+
diff --git a/src/nepi/resources/ns3/ns3dceapplication.py b/src/nepi/resources/ns3/ns3dceapplication.py
new file mode 100644 (file)
index 0000000..acaf0e6
--- /dev/null
@@ -0,0 +1,170 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import clsinit_copy, ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3application import NS3BaseApplication
+
+import os
+
+@clsinit_copy
+class NS3BaseDceApplication(NS3BaseApplication):
+    _rtype = "abstract::ns3::DceApplication"
+
+    @classmethod
+    def _register_attributes(cls):
+        binary = Attribute("binary", 
+                "Name of binary to execute",
+                flags = Flags.Design)
+
+        stack_size = Attribute("stackSize", 
+                "Stack Size for DCE",
+                type = Types.Integer,
+                default = 1<<20,                
+                flags = Flags.Design)
+
+        arguments = Attribute("arguments", 
+                "Semi-colon separated list of arguments for the application",
+                flags = Flags.Design)
+
+        environment = Attribute("environment", 
+                "Semi-colon separated list of 'key=value' pairs to set as "
+                "DCE environment variables.",
+                flags = Flags.Design)
+
+        cls._register_attribute(binary)
+        cls._register_attribute(stack_size)
+        cls._register_attribute(arguments)
+        cls._register_attribute(environment)
+
+    @property
+    def node(self):
+        from nepi.resources.ns3.ns3node import NS3BaseNode
+        nodes = self.get_connected(NS3BaseNode.get_rtype())
+
+        if not nodes: 
+            msg = "DceApplication not connected to node"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        if nodes[0].get("enableDCE") == False:
+            raise RuntimeError("DceApplication not connected to DCE enabled node")
+
+        return nodes[0]
+    
+    def _instantiate_object(self):
+        pass
+
+    def _connect_object(self):
+        node = self.node
+        if node.uuid not in self.connected:
+            self._connected.add(node.uuid)
+
+            # Preventing concurrent access to the DceApplicationHelper
+            # from different DceApplication RMs
+            with self.simulation.dce_application_lock:
+                self.simulation.invoke(
+                        self.simulation.dce_application_helper_uuid, 
+                        "ResetArguments") 
+
+                self.simulation.invoke(
+                        self.simulation.dce_application_helper_uuid, 
+                        "ResetEnvironment") 
+
+                self.simulation.invoke(
+                        self.simulation.dce_application_helper_uuid, 
+                        "SetBinary", self.get("binary")) 
+
+                self.simulation.invoke(
+                        self.simulation.dce_application_helper_uuid, 
+                        "SetStackSize", self.get("stackSize")) 
+
+                arguments = self.get("arguments") or ""
+                for arg in map(str.strip, arguments.split(";")):
+                    self.simulation.invoke(
+                            self.simulation.dce_application_helper_uuid, 
+                        "AddArgument", arg)
+
+                environment = self.get("environment") or ""
+                for env in map(str.strip, environment.split(";")):
+                    key, val = env.split("=")
+                    self.simulation.invoke(
+                            self.simulation.dce_application_helper_uuid, 
+                        "AddEnvironment", key, val)
+
+                if self.has_attribute("files"):
+                    files = self.get("files") or ""
+                    for files in map(str.strip, files.split(";")):
+                        remotepath, dcepath = env.split("=")
+                        localpath = "${SHARE}/" + os.path.basename(remotepath)
+                        self.simulation.invoke(
+                                self.simulation.dce_application_helper_uuid, 
+                            "AddFile", localpath, dcepath)
+
+                if self.has_attribute("stdinFile"):
+                    stdinfile = self.get("stdinFile")
+                    if stdinfile:
+                        if stdinfile != "":
+                            stdinfile = "${SHARE}/" + os.path.basename(stdinfile)
+        
+                        self.simulation.invoke(
+                                self.simulation.dce_application_helper_uuid, 
+                                "SetStdinFile", stdinfile)
+
+                apps_uuid = self.simulation.invoke(
+                        self.simulation.dce_application_helper_uuid, 
+                        "InstallInNode", self.node.uuid)
+
+            self._uuid = self.simulation.invoke(apps_uuid, "Get", 0)
+
+            if self.has_changed("StartTime"):
+                self.simulation.ns3_set(self.uuid, "StartTime", self.get("StartTime"))
+
+            if self.has_changed("StopTime"):
+                self.simulation.ns3_set(self.uuid, "StopTime", self.get("StopTime"))
+
+    def do_stop(self):
+        if self.state == ResourceState.STARTED:
+            # No need to do anything, simulation.Destroy() will stop every object
+            self.info("Stopping command '%s'" % command)
+            self.simulation.invoke(self.uuid, "Stop")
+            self.set_stopped()
+
+    def do_start(self):
+        if self.simulation.state < ResourceState.STARTED:
+            self.debug("---- RESCHEDULING START ----" )
+            self.ec.schedule(reschedule_delay, self.start)
+        else:
+            self._configure_traces()
+            super(NS3BaseApplication, self).do_start()
+            self._start_time = self.simulation.start_time
+
+    def _configure_traces(self):
+        # Preventing concurrent access to the DceApplicationHelper
+        # from different DceApplication RMs
+        with self.simulation.dce_application_lock:
+            pid = self.simulation.invoke(self.simulation.dce_application_helper_uuid, 
+                    "GetPid", self._uuid)
+        node_id = self.simulation.invoke(self.node.uuid, "GetId")
+        self._trace_filename["stdout"] = "files-%s/var/log/%s/stdout" % (node_id, pid)
+        self._trace_filename["stderr"] = "files-%s/var/log/%s/stderr" % (node_id, pid)
+        self._trace_filename["status"] = "files-%s/var/log/%s/status" % (node_id, pid)
+        self._trace_filename["cmdline"] = "files-%s/var/log/%s/cmdline" % (node_id, pid)
+
+
diff --git a/src/nepi/resources/ns3/ns3errormodel.py b/src/nepi/resources/ns3/ns3errormodel.py
new file mode 100644 (file)
index 0000000..d46293f
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseErrorModel(NS3Base):
+    _rtype = "abstract::ns3::ErrorModel"
+
+    @property
+    def device(self):
+        from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
+        devices = self.get_connected(NS3BaseNetDevice.get_rtype())
+
+        if not devices: 
+            msg = "ErrorModel not connected to device"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return devices[0]
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.device)
+        return rms
+
+    def _connect_object(self):
+        device = self.device
+        if device.uuid not in self.connected:
+            self.simulation.invoke(device.uuid, "SetReceiveErrorModel", self.uuid)
+            self._connected.add(device.uuid)
+
diff --git a/src/nepi/resources/ns3/ns3errorratemodel.py b/src/nepi/resources/ns3/ns3errorratemodel.py
new file mode 100644 (file)
index 0000000..961b541
--- /dev/null
@@ -0,0 +1,54 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseErrorRateModel(NS3Base):
+    _rtype = "abstract::ns3::ErrorRateModel"
+
+    @property
+    def node(self):
+        return self.phy.node
+
+    @property
+    def phy(self):
+        from nepi.resources.ns3.ns3wifiphy import NS3BaseWifiPhy
+        phys = self.get_connected(NS3BaseWifiPhy.get_rtype())
+
+        if not phys: 
+            msg = "ErrorRateModel not connected to phy"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return phys[0]
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.phy)
+        return rms
+
+    def _connect_object(self):
+        phy = self.phy
+        if phy.uuid not in self.connected:
+            self.simulation.invoke(phy.uuid, "SetErrorRateModel", self.uuid)
+            self._connected.add(phy.uuid)
+
diff --git a/src/nepi/resources/ns3/ns3icmpv4l4protocol.py b/src/nepi/resources/ns3/ns3icmpv4l4protocol.py
new file mode 100644 (file)
index 0000000..94f8128
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseIcmpv4L4Protocol(NS3Base):
+    _rtype = "abstract::ns3::Icmpv4L4Protocol"
+
+    @property
+    def node(self):
+        from nepi.resources.ns3.ns3node import NS3BaseNode
+        nodes = self.get_connected(NS3BaseNode.get_rtype())
+
+        if not nodes: 
+            msg = "Icmp4L4Protocol not connected to node"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return nodes[0]
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.node)
+        return rms
+
diff --git a/src/nepi/resources/ns3/ns3ipv4l3protocol.py b/src/nepi/resources/ns3/ns3ipv4l3protocol.py
new file mode 100644 (file)
index 0000000..5d53943
--- /dev/null
@@ -0,0 +1,66 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseIpv4L3Protocol(NS3Base):
+    _rtype = "abstract::ns3::Ipv4L3Protocol"
+
+    def __init__(self, ec, guid):
+        super(NS3BaseIpv4L3Protocol, self).__init__(ec, guid)
+        self.list_routing_uuid = None
+        self.static_routing_uuid = None
+        self.global_routing_uuid = None
+
+    @property
+    def node(self):
+        from nepi.resources.ns3.ns3node import NS3BaseNode
+        nodes = self.get_connected(NS3BaseNode.get_rtype())
+
+        if not nodes: 
+            msg = "Ipv4L3Protocol not connected to node"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return nodes[0]
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.simulation)
+        return rms
+
+    def _configure_object(self):
+        simulation = self.simulation
+
+        self.list_routing_uuid = simulation.create("Ipv4ListRouting")
+        simulation.invoke(self.uuid, "SetRoutingProtocol", self.list_routing_uuid)
+
+        self.static_routing_uuid = simulation.create("Ipv4StaticRouting")
+        simulation.invoke(self.list_routing_uuid, "AddRoutingProtocol", 
+                self.static_routing_uuid, 0)
+
+        self.global_routing_uuid = simulation.create("Ipv4GlobalRouting")
+        simulation.invoke(self.list_routing_uuid, "AddRoutingProtocol", 
+                self.global_routing_uuid, -10)
+
+    def _connect_object(self):
+        pass
diff --git a/src/nepi/resources/ns3/ns3mobilitymodel.py b/src/nepi/resources/ns3/ns3mobilitymodel.py
new file mode 100644 (file)
index 0000000..4e1a0e0
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+# TODO: 
+#       - mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
+#       - set hook for Position - SetPosition(Vector)
+
+@clsinit_copy
+class NS3BaseMobilityModel(NS3Base):
+    _rtype = "abstract::ns3::MobilityModel"
+
+    def _configure_object(self):
+        # Set initial position
+        position = self.get("Position")
+        if position:
+            self.simulation.ns3_set(self.uuid, "Position", position)
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.simulation)
+        return rms
+
+    def _connect_object(self):
+        pass
diff --git a/src/nepi/resources/ns3/ns3netdevice.py b/src/nepi/resources/ns3/ns3netdevice.py
new file mode 100644 (file)
index 0000000..f136dd8
--- /dev/null
@@ -0,0 +1,231 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags
+from nepi.execution.resource import clsinit_copy
+from nepi.execution.trace import Trace
+from nepi.resources.ns3.ns3base import NS3Base
+
+import ipaddr
+
+@clsinit_copy
+class NS3BaseNetDevice(NS3Base):
+    _rtype = "abstract::ns3::NetDevice"
+
+    @classmethod
+    def _register_attributes(cls):
+        mac = Attribute("mac", "MAC address for device",
+                flags = Flags.Design)
+
+        ip = Attribute("ip", "IP address for device",
+                flags = Flags.Design)
+
+        prefix = Attribute("prefix", "Network prefix for device",
+                flags = Flags.Design)
+
+        cls._register_attribute(mac)
+        cls._register_attribute(ip)
+        cls._register_attribute(prefix)
+
+    @classmethod
+    def _register_traces(cls):
+        pcap = Trace("pcap", "Dump traffic sniffed on the network device in Pcap format")
+        promisc_pcap = Trace("promiscPcap", "Dump traffic sniffed in promiscuous mode on the network device in Pcap format")
+        ascii = Trace("ascii", "Dump traffic sniffed on the network device in Ascii format")
+
+        cls._register_trace(pcap)
+        cls._register_trace(promisc_pcap)
+        cls._register_trace(ascii)
+
+    def __init__(self, ec, guid):
+        super(NS3BaseNetDevice, self).__init__(ec, guid)
+        self._ascii_helper_uuid = None
+        self._device_helper_uuid = None
+
+    @property
+    def node(self):
+        from nepi.resources.ns3.ns3node import NS3BaseNode
+        nodes = self.get_connected(NS3BaseNode.get_rtype())
+
+        if not nodes: 
+            msg = "Device not connected to node"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return nodes[0]
+
+    @property
+    def channel(self):
+        from nepi.resources.ns3.ns3channel import NS3BaseChannel
+        channels = self.get_connected(NS3BaseChannel.get_rtype())
+
+        if not channels: 
+            msg = "Device not connected to channel"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return channels[0]
+
+    @property
+    def queue(self):
+        from nepi.resources.ns3.ns3queue import NS3BaseQueue
+        queue = self.get_connected(NS3BaseQueue.get_rtype())
+
+        if not queue: 
+            msg = "Device not connected to queue"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return queue[0]
+
+    @property
+    def ascii_helper_uuid(self):
+        if not self._ascii_helper_uuid:
+            self._ascii_helper_uuid = self.simulation.create("AsciiTraceHelper")
+        return self._ascii_helper_uuid
+
+    @property
+    def device_helper_uuid(self):
+        if not self._device_helper_uuid:
+            rtype = self.get_rtype()
+            if rtype == "ns3::PointToPointNetDevice":
+                classname = "PointToPointHelper"
+            elif rtype == "ns3::CsmaNetDevice":
+                classname = "CsmaHelper"
+            elif rtype == "ns3::EmuNetDevice":
+                classname = "EmuHelper"
+            elif rtype == "ns3::FdNetDevice":
+                classname = "FdNetDeviceHelper"
+            elif rtype in [ "ns3::BaseStationNetDevice", "SubscriberStationNetDevice" ]:
+                classname = "WimaxHelper"
+            elif rtype == "ns3::WifiNetDevice":
+                classname = "YansWifiPhyHelper"
+
+            self._device_helper_uuid = self.simulation.create(classname)
+
+        return self._device_helper_uuid
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        
+        node = self.node
+        rms.add(node)
+
+        ipv4 = node.ipv4
+        if node.ipv4:
+            rms.add(ipv4)
+
+        rms.add(self.channel)
+        return rms
+
+    def _configure_object(self):
+        # Set Mac
+        self._configure_mac_address()
+
+        # Set IP address
+        self._configure_ip_address()
+        
+        # Enable traces
+        self._configure_traces()
+
+    def _configure_mac_address(self):
+        mac = self.get("mac")
+        if mac:
+            mac_uuid = self.simulation.create("Mac48Address", mac)
+        else:
+            mac_uuid = self.simulation.invoke("singleton::Mac48Address", "Allocate")
+
+        self.simulation.invoke(self.uuid, "SetAddress", mac_uuid)
+
+    def _configure_ip_address(self):
+        ip = self.get("ip")
+        prefix = self.get("prefix")
+
+        i = ipaddr.IPAddress(ip)
+        if i.version == 4:
+            # IPv4
+            ipv4 = self.node.ipv4
+            ifindex_uuid = self.simulation.invoke(ipv4.uuid, "AddInterface", 
+                    self.uuid)
+            ipv4_addr_uuid = self.simulation.create("Ipv4Address", ip)
+            ipv4_mask_uuid = self.simulation.create("Ipv4Mask", "/%s" % str(prefix))
+            inaddr_uuid = self.simulation.create("Ipv4InterfaceAddress", 
+                    ipv4_addr_uuid, ipv4_mask_uuid)
+            self.simulation.invoke(ipv4.uuid, "AddAddress", ifindex_uuid, 
+                    inaddr_uuid)
+            self.simulation.invoke(ipv4.uuid, "SetMetric", ifindex_uuid, 1)
+            self.simulation.invoke(ipv4.uuid, "SetUp", ifindex_uuid)
+        else:
+            # IPv6
+            # TODO!
+            pass
+
+    def _configure_traces(self):
+        if self.trace_enabled("pcap"):
+            helper_uuid = self.device_helper_uuid
+
+            filename = "trace-pcap-netdev-%d.pcap" % self.guid
+            self._trace_filename["pcap"] = filename
+
+            filepath = self.simulation.trace_filepath(filename)
+
+            self.simulation.invoke(helper_uuid, "EnablePcap", filepath, 
+                    self.uuid, promiscuous = False, explicitFilename = True)
+
+        if self.trace_enabled("promiscPcap"):
+            helper_uuid = self.device_helper_uuid
+
+            filename = "trace-promisc-pcap-netdev-%d.pcap" % self.guid
+            self._trace_filename["promiscPcap"] = filename
+
+            filepath = self.simulation.trace_filepath(filename)
+
+            self.simulation.invoke(helper_uuid, "EnablePcap", filepath, 
+                    self.uuid, promiscuous = True, explicitFilename = True)
+
+        if self.trace_enabled("ascii"):
+            helper_uuid = self.device_helper_uuid
+            ascii_helper_uuid = self.ascii_helper_uuid
+
+            filename = "trace-ascii-netdev-%d.tr" % self.guid
+            self._trace_filename["ascii"] = filename
+
+            filepath = self.simulation.trace_filepath(filename)
+            stream_uuid = self.simulation.invoke(ascii_helper_uuid, 
+                    "CreateFileStream", filepath) 
+            self.simulation.invoke(helper_uuid, "EnableAscii", stream_uuid,
+                    self.uuid)
+
+    def _connect_object(self):
+        node = self.node
+        if node and node.uuid not in self.connected:
+            self.simulation.invoke(node.uuid, "AddDevice", self.uuid)
+            self._connected.add(node.uuid)
+
+        channel = self.channel
+        if channel and channel.uuid not in self.connected:
+            self.simulation.invoke(self.uuid, "Attach", channel.uuid)
+            self._connected.add(channel.uuid)
+        
+        queue = self.queue
+        # Verify that the device has a queue. If no queue is added a segfault 
+        # error occurs
+        if queue and queue.uuid not in self.connected:
+            self._connected.add(queue.uuid)
diff --git a/src/nepi/resources/ns3/ns3node.py b/src/nepi/resources/ns3/ns3node.py
new file mode 100644 (file)
index 0000000..b6188e3
--- /dev/null
@@ -0,0 +1,114 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseNode(NS3Base):
+    _rtype = "abstract::ns3::Node"
+
+    @classmethod
+    def _register_attributes(cls):
+        enable_dce = Attribute("enableDCE", 
+                "This node will run in DCE emulation mode ",
+                default = False,
+                type = Types.Bool,
+                flags = Flags.Design)
+
+        cls._register_attribute(enable_dce)
+
+    @property
+    def simulation(self):
+        from nepi.resources.ns3.ns3simulation import NS3Simulation
+        for guid in self.connections:
+            rm = self.ec.get_resource(guid)
+            if isinstance(rm, NS3Simulation):
+                return rm
+
+        msg = "Node not connected to simulation"
+        self.error(msg)
+        raise RuntimeError, msg
+    @property
+    def ipv4(self):
+        from nepi.resources.ns3.ns3ipv4l3protocol import NS3BaseIpv4L3Protocol
+        ipv4s = self.get_connected(NS3BaseIpv4L3Protocol.get_rtype())
+        if ipv4s: return ipv4s[0]
+        return None
+
+    @property
+    def mobility(self):
+        from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel
+        mobility = self.get_connected(NS3BaseMobilityModel.get_rtype())
+        if mobility: return mobility[0]
+        return None
+
+    @property
+    def devices(self):
+        from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
+        devices = self.get_connected(NS3BaseNetDevice.get_rtype())
+
+        if not devices: 
+            msg = "Node not connected to devices"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return devices
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.simulation)
+
+        ipv4 = self.ipv4
+        if ipv4:
+            rms.add(ipv4)
+
+        mobility = self.mobility
+        if mobility:
+            rms.add(mobility)
+
+        return rms
+
+    def _configure_object(self):
+        ### node.AggregateObject(PacketSocketFactory())
+        uuid_packet_socket_factory = self.simulation.create("PacketSocketFactory")
+        self.simulation.invoke(self.uuid, "AggregateObject", uuid_packet_socket_factory)
+
+        if self.get("enableDCE") == True:
+            self._add_dce()
+
+    def _connect_object(self):
+        ipv4 = self.ipv4
+        if ipv4:
+            self.simulation.invoke(self.uuid, "AggregateObject", ipv4.uuid)
+
+        mobility = self.mobility
+        if mobility:
+            self.simulation.invoke(self.uuid, "AggregateObject", mobility.uuid)
+
+    def _add_dce(self):
+        container_uuid = self.simulation.create("NodeContainer")
+        self.simulation.invoke(container_uuid, "Add", self.uuid)
+        with self.simulation.dce_manager_lock:
+            self.simulation.invoke(self.simulation.dce_manager_helper_uuid, 
+                    "Install", container_uuid)
+
diff --git a/src/nepi/resources/ns3/ns3propagationdelaymodel.py b/src/nepi/resources/ns3/ns3propagationdelaymodel.py
new file mode 100644 (file)
index 0000000..f091ec8
--- /dev/null
@@ -0,0 +1,54 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BasePropagationDelayModel(NS3Base):
+    _rtype = "abstract::ns3::PropagationDelayModel"
+
+    @property
+    def simulation(self):
+        return self.channel.simulation
+
+    @property
+    def channel(self):
+        from nepi.resources.ns3.ns3wifichannel import NS3BaseWifiChannel
+        channels = self.get_connected(NS3BaseWifiChannel.get_rtype())
+
+        if not channels: 
+            msg = "PropagationDelayModel not connected to channel"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return channels[0]
+
+    @property
+    def _rms_to_wait(self):
+        others = set()
+        others.add(self.channel)
+        return others
+
+    def _connect_object(self):
+        channel = self.channel
+        if channel.uuid not in self.connected:
+            self.simulation.invoke(channel.uuid, "SetPropagationDelayModel", self.uuid)
+            self._connected.add(channel.uuid)
+
diff --git a/src/nepi/resources/ns3/ns3propagationlossmodel.py b/src/nepi/resources/ns3/ns3propagationlossmodel.py
new file mode 100644 (file)
index 0000000..94d0dab
--- /dev/null
@@ -0,0 +1,54 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BasePropagationLossModel(NS3Base):
+    _rtype = "ns3::PropagationLossModel"
+
+    @property
+    def simulation(self):
+        return self.channel.simulation
+
+    @property
+    def channel(self):
+        from nepi.resources.ns3.ns3wifichannel import NS3BaseWifiChannel
+        channels = self.get_connected(NS3BaseWifiChannel.get_rtype())
+
+        if not channels: 
+            msg = "PropagationLossModel not connected to channel"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return channels[0]
+
+    @property
+    def _rms_to_wait(self):
+        others = set()
+        others.add(self.channel)
+        return others
+
+    def _connect_object(self):
+        channel = self.channel
+        if channel.uuid not in self.connected:
+            self.simulation.invoke(channel.uuid, "SetPropagationLossModel", self.uuid)
+            self._connected.add(channel.uuid)
+
diff --git a/src/nepi/resources/ns3/ns3queue.py b/src/nepi/resources/ns3/ns3queue.py
new file mode 100644 (file)
index 0000000..d7ec2b7
--- /dev/null
@@ -0,0 +1,54 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseQueue(NS3Base):
+    _rtype = "abstract::ns3::Queue"
+
+    @property
+    def device(self):
+        from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
+        devices = self.get_connected(NS3BaseNetDevice.get_rtype())
+
+        if not devices: 
+            msg = "Queue not connected to device"
+            self.error(msg, out, err)
+            raise RuntimeError, msg
+
+        return devices[0]
+
+    @property
+    def node(self):
+        return self.device.node
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.device)
+        return rms
+
+    def _connect_object(self):
+        device = self.device
+        if device.uuid not in self.connected:
+            self.simulation.invoke(device.uuid, "SetQueue", self.uuid)
+            self._connected.add(device.uuid)
+
diff --git a/src/nepi/resources/ns3/ns3route.py b/src/nepi/resources/ns3/ns3route.py
new file mode 100644 (file)
index 0000000..bb61368
--- /dev/null
@@ -0,0 +1,93 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags
+from nepi.execution.resource import clsinit_copy
+from nepi.execution.trace import Trace
+from nepi.resources.ns3.ns3base import NS3Base
+
+import ipaddr
+
+@clsinit_copy
+class NS3Route(NS3Base):
+    _rtype = "ns3::Route"
+
+    @classmethod
+    def _register_attributes(cls):
+        network = Attribute("network", "Destination network address",
+                flags = Flags.Design)
+
+        prefix = Attribute("prefix", "Network prefix for the network",
+                flags = Flags.Design)
+
+        nexthop = Attribute("nexthop", "Address of next hop in the route",
+                flags = Flags.Design)
+
+        cls._register_attribute(network)
+        cls._register_attribute(prefix)
+        cls._register_attribute(nexthop)
+
+    def __init__(self, ec, guid):
+        super(NS3Route, self).__init__(ec, guid)
+
+    @property
+    def node(self):
+        from nepi.resources.ns3.ns3node import NS3BaseNode
+        nodes = self.get_connected(NS3BaseNode.get_rtype())
+
+        if not nodes: 
+            msg = "Device not connected to node"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return nodes[0]
+
+    @property
+    def _rms_to_wait(self):
+        # Wait for all network devices connected to the node to be ready
+        # before configuring the routes, else the route might refer to a
+        # non yet existing interface
+
+        rms = set()
+        rms.update(self.node.devices)
+        return rms
+
+    def _instantiate_object(self):
+        pass
+
+    def _configure_object(self):
+        network = self.get("network")
+        prefix = self.get("prefix")
+        nexthop = self.get("nexthop")
+        ipv4_uuid = self.node.ipv4.uuid
+
+        ret = self.simulation.invoke(ipv4_uuid, "addStaticRoute", network, 
+            prefix, nexthop)
+
+        if not ret: 
+            msg = "Could not configure route %s/%s hop: %s" % (network, prefix, 
+                    nexthop)
+            self.error(msg)
+            raise RuntimeError, msg
+
+    def _connect_object(self):
+        node = self.node
+        if node and node.uuid not in self.connected:
+            self._connected.add(node.uuid)
+
diff --git a/src/nepi/resources/ns3/ns3server.py b/src/nepi/resources/ns3/ns3server.py
new file mode 100644 (file)
index 0000000..f761b86
--- /dev/null
@@ -0,0 +1,254 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+import base64
+import cPickle
+import errno
+import logging
+import os
+import socket
+import sys
+
+from optparse import OptionParser, SUPPRESS_HELP
+
+from ns3wrapper import NS3Wrapper
+
+class NS3WrapperMessage:
+    CREATE = "CREATE"
+    FACTORY = "FACTORY"
+    INVOKE = "INVOKE"
+    SET = "SET"
+    GET = "GET"
+    FLUSH = "FLUSH"
+    START = "START"
+    STOP = "STOP"
+    SHUTDOWN = "SHUTDOWN"
+
+def handle_message(ns3_wrapper, msg_type, args, kwargs):
+    if msg_type == NS3WrapperMessage.SHUTDOWN:
+        ns3_wrapper.shutdown()
+        
+        ns3_wrapper.logger.debug("SHUTDOWN")
+        
+        return "BYEBYE"
+    
+    if msg_type == NS3WrapperMessage.STOP:
+        time = kwargs.get("time")
+
+        ns3_wrapper.logger.debug("STOP time=%s" % str(time))
+
+        ns3_wrapper.stop(time=time)
+        return "STOPPED"
+
+    if msg_type == NS3WrapperMessage.START:
+        ns3_wrapper.logger.debug("START") 
+
+        ns3_wrapper.start()
+        return "STARTED"
+
+    if msg_type == NS3WrapperMessage.CREATE:
+        clazzname = args.pop(0)
+        
+        ns3_wrapper.logger.debug("CREATE %s %s" % (clazzname, str(args)))
+
+        uuid = ns3_wrapper.create(clazzname, *args)
+        return uuid
+
+    if msg_type == NS3WrapperMessage.FACTORY:
+        type_name = args.pop(0)
+
+        ns3_wrapper.logger.debug("FACTORY %s %s" % (type_name, str(kwargs)))
+
+        uuid = ns3_wrapper.factory(type_name, **kwargs)
+        return uuid
+
+    if msg_type == NS3WrapperMessage.INVOKE:
+        uuid = args.pop(0)
+        operation = args.pop(0)
+        
+        ns3_wrapper.logger.debug("INVOKE %s %s %s %s " % (uuid, operation, 
+            str(args), str(kwargs)))
+    
+        uuid = ns3_wrapper.invoke(uuid, operation, *args, **kwargs)
+        return uuid
+
+    if msg_type == NS3WrapperMessage.GET:
+        uuid = args.pop(0)
+        name = args.pop(0)
+
+        ns3_wrapper.logger.debug("GET %s %s" % (uuid, name))
+
+        value = ns3_wrapper.get(uuid, name)
+        return value
+
+    if msg_type == NS3WrapperMessage.SET:
+        uuid = args.pop(0)
+        name = args.pop(0)
+        value = args.pop(0)
+
+        ns3_wrapper.logger.debug("SET %s %s %s" % (uuid, name, str(value)))
+
+        value = ns3_wrapper.set(uuid, name, value)
+        return value
+    if msg_type == NS3WrapperMessage.FLUSH:
+        # Forces flushing output and error streams.
+        # NS-3 output will stay unflushed until the program exits or 
+        # explicit invocation flush is done
+        sys.stdout.flush()
+        sys.stderr.flush()
+
+        ns3_wrapper.logger.debug("FLUSHED") 
+        
+        return "FLUSHED"
+
+def create_socket(socket_name):
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    sock.bind(socket_name)
+    return sock
+
+def recv_msg(conn):
+    msg = []
+    chunk = ''
+
+    while '\n' not in chunk:
+        try:
+            chunk = conn.recv(1024)
+        except (OSError, socket.error), e:
+            if e[0] != errno.EINTR:
+                raise
+            # Ignore eintr errors
+            continue
+
+        if chunk:
+            msg.append(chunk)
+        else:
+            # empty chunk = EOF
+            break
+    msg = ''.join(msg).strip()
+
+    # The message is formatted as follows:
+    #   MESSAGE_TYPE|args|kwargs
+    #
+    #   where MESSAGE_TYPE, args and kwargs are pickld and enoded in base64
+
+    def decode(item):
+        item = base64.b64decode(item).rstrip()
+        return cPickle.loads(item)
+
+    decoded = map(decode, msg.split("|"))
+
+    # decoded message
+    dmsg_type = decoded.pop(0)
+    dargs = list(decoded.pop(0)) # transforming touple into list
+    dkwargs = decoded.pop(0)
+
+    return (dmsg_type, dargs, dkwargs)
+
+def send_reply(conn, reply):
+    encoded = base64.b64encode(cPickle.dumps(reply))
+    conn.send("%s\n" % encoded)
+
+def get_options():
+    usage = ("usage: %prog -S <socket-name> -L <NS_LOG> -v ")
+    
+    parser = OptionParser(usage = usage)
+
+    parser.add_option("-S", "--socket-name", dest="socket_name",
+        help = "Name for the unix socket used to interact with this process", 
+        default = "tap.sock", type="str")
+
+    parser.add_option("-L", "--ns-log", dest="ns_log",
+        help = "NS_LOG environmental variable to be set", 
+        default = "", type="str")
+
+    parser.add_option("-v", "--verbose",
+        help="Print debug output",
+        action="store_true", 
+        dest="verbose", default=False)
+
+    (options, args) = parser.parse_args()
+    
+    return (options.socket_name, options.verbose, options.ns_log)
+
+def run_server(socket_name, level = logging.INFO, ns_log = None):
+
+    # Sets NS_LOG environmental variable for NS debugging
+    if ns_log:
+        os.environ["NS_LOG"] = ns_log
+
+    ###### ns-3 wrapper instantiation
+
+    ns3_wrapper = NS3Wrapper(loglevel=level)
+    
+    ns3_wrapper.logger.info("STARTING...")
+
+    # create unix socket to receive instructions
+    sock = create_socket(socket_name)
+    sock.listen(0)
+
+    # wait for messages to arrive and process them
+    stop = False
+
+    while not stop:
+        conn, addr = sock.accept()
+        conn.settimeout(5)
+
+        try:
+            (msg_type, args, kwargs) = recv_msg(conn)
+        except socket.timeout, e:
+            # Ingore time-out
+            continue
+
+        if not msg_type:
+            # Ignore - connection lost
+            break
+
+        if msg_type == NS3WrapperMessage.SHUTDOWN:
+           stop = True
+  
+        try:
+            reply = handle_message(ns3_wrapper, msg_type, args, kwargs)  
+        except:
+            import traceback
+            err = traceback.format_exc()
+            ns3_wrapper.logger.error(err) 
+            raise
+
+        try:
+            send_reply(conn, reply)
+        except socket.error:
+            break
+        
+    ns3_wrapper.logger.info("EXITING...")
+
+if __name__ == '__main__':
+            
+    (socket_name, verbose, ns_log) = get_options()
+
+    ## configure logging
+    FORMAT = "%(asctime)s %(name)s %(levelname)-4s %(message)s"
+    level = logging.DEBUG if verbose else logging.INFO
+
+    logging.basicConfig(format = FORMAT, level = level)
+
+    ## Run the server
+    run_server(socket_name, level, ns_log)
+
diff --git a/src/nepi/resources/ns3/ns3simulation.py b/src/nepi/resources/ns3/ns3simulation.py
new file mode 100644 (file)
index 0000000..f98237f
--- /dev/null
@@ -0,0 +1,51 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+class NS3Simulation(object):
+    @property
+    def client(self):
+        return self._client
+
+    def create(self, *args, **kwargs):
+        return self.client.create(*args, **kwargs)
+
+    def factory(self, *args, **kwargs):
+        return self.client.factory(*args, **kwargs)
+
+    def invoke(self, *args, **kwargs):
+        return self.client.invoke(*args, **kwargs)
+
+    def ns3_set(self, *args, **kwargs):
+        return self.client.set(*args, **kwargs)
+
+    def ns3_get(self, *args, **kwargs):
+        return self.client.get(*args, **kwargs)
+
+    def flush(self, *args, **kwargs):
+        return self.client.flush(*args, **kwargs)
+
+    def start(self, *args, **kwargs):
+        return self.client.start(*args, **kwargs)
+
+    def stop(self, *args, **kwargs):
+        return self.client.stop(*args, **kwargs)
+
+    def shutdown(self, *args, **kwargs):
+        return self.client.shutdown(*args, **kwargs)
+
diff --git a/src/nepi/resources/ns3/ns3wifichannel.py b/src/nepi/resources/ns3/ns3wifichannel.py
new file mode 100644 (file)
index 0000000..3942e8c
--- /dev/null
@@ -0,0 +1,51 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+class NS3BaseWifiChannel(NS3Base):
+    _rtype = "abstract::ns3::WifiChannel"
+
+    @property
+    def simulation(self):
+        return self.phys[0].device.node.simulation
+
+    @property
+    def phys(self):
+        from nepi.resources.ns3.ns3wifiphy import NS3BaseWifiPhy
+        phys = self.get_connected(NS3BaseWifiPhy.get_rtype())
+
+        if not phys: 
+            msg = "Channel not connected to phy"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return phys
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.simulation)
+        return rms
+
+    def _connect_object(self):
+        pass
+
diff --git a/src/nepi/resources/ns3/ns3wifimac.py b/src/nepi/resources/ns3/ns3wifimac.py
new file mode 100644 (file)
index 0000000..e8ab8b6
--- /dev/null
@@ -0,0 +1,80 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+from nepi.resources.ns3.ns3wifinetdevice import WIFI_STANDARDS
+
+@clsinit_copy
+class NS3BaseWifiMac(NS3Base):
+    _rtype = "abstract::ns3::WifiMac"
+
+    @classmethod
+    def _register_attributes(cls):
+        standard = Attribute("Standard", "Wireless standard",
+                default = "WIFI_PHY_STANDARD_80211a",
+                allowed = WIFI_STANDARDS.keys(),
+                type = Types.Enumerate,
+                flags = Flags.Design)
+
+        cls._register_attribute(standard)
+
+    @property
+    def node(self):
+        return self.device.node
+
+    @property
+    def device(self):
+        from nepi.resources.ns3.ns3wifinetdevice import NS3BaseWifiNetDevice
+        devices = self.get_connected(NS3BaseWifiNetDevice.get_rtype())
+
+        if not devices: 
+            msg = "WifiMac not connected to device"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return devices[0]
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.device)
+        return rms
+
+    def _connect_object(self):
+        device = self.device
+        if device.uuid not in self.connected:
+            self._connected.add(device.uuid)
+
+            self.simulation.invoke(device.uuid, "SetMac", self.uuid)
+
+            standard = self.get("Standard")
+            self.simulation.invoke(self.uuid, "ConfigureStandard", WIFI_STANDARDS[standard])
+
+            # Delayed configuration of MAC address
+            mac = device.get("mac")
+            if mac:
+                mac_uuid = self.simulation.create("Mac48Address", mac)
+            else:
+                mac_uuid = self.simulation.invoke("singleton::Mac48Address", "Allocate")
+
+            self.simulation.invoke(self.uuid, "SetAddress", mac_uuid)
+
+
diff --git a/src/nepi/resources/ns3/ns3wifinetdevice.py b/src/nepi/resources/ns3/ns3wifinetdevice.py
new file mode 100644 (file)
index 0000000..ea700ea
--- /dev/null
@@ -0,0 +1,62 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
+
+WIFI_STANDARDS = dict({
+    "WIFI_PHY_STANDARD_holland": 5,
+    "WIFI_PHY_STANDARD_80211p_SCH": 7,
+    "WIFI_PHY_STANDARD_80211_5Mhz": 4,
+    "WIFI_PHY_UNKNOWN": 8,
+    "WIFI_PHY_STANDARD_80211_10Mhz": 3,
+    "WIFI_PHY_STANDARD_80211g": 2,
+    "WIFI_PHY_STANDARD_80211p_CCH": 6,
+    "WIFI_PHY_STANDARD_80211a": 0,
+    "WIFI_PHY_STANDARD_80211b": 1
+})
+
+@clsinit_copy
+class NS3BaseWifiNetDevice(NS3BaseNetDevice):
+    _rtype = "abstract::ns3::WifiNetDevice"
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        
+        node = self.node
+        rms.add(node)
+
+        ipv4 = node.ipv4
+        if node.ipv4:
+            rms.add(ipv4)
+
+        return rms
+
+    def _configure_mac_address(self):
+        # The wifimac is the one responsible for
+        # configuring the MAC address
+        pass
+
+    def _connect_object(self):
+        node = self.node
+        if node and node.uuid not in self.connected:
+            self.simulation.invoke(node.uuid, "AddDevice", self.uuid)
+            self._connected.add(node.uuid)
+
diff --git a/src/nepi/resources/ns3/ns3wifiphy.py b/src/nepi/resources/ns3/ns3wifiphy.py
new file mode 100644 (file)
index 0000000..4ea0248
--- /dev/null
@@ -0,0 +1,88 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+from nepi.resources.ns3.ns3wifinetdevice import WIFI_STANDARDS
+
+@clsinit_copy
+class NS3BaseWifiPhy(NS3Base):
+    _rtype = "abstract::ns3::WifiPhy"
+
+    @classmethod
+    def _register_attributes(cls):
+        standard = Attribute("Standard", "Wireless standard",
+                default = "WIFI_PHY_STANDARD_80211a",
+                allowed = WIFI_STANDARDS.keys(),
+                type = Types.Enumerate,
+                flags = Flags.Design)
+
+        cls._register_attribute(standard)
+
+    @property
+    def node(self):
+        return self.device.node
+
+    @property
+    def device(self):
+        from nepi.resources.ns3.ns3wifinetdevice import NS3BaseWifiNetDevice
+        devices = self.get_connected(NS3BaseWifiNetDevice.get_rtype())
+
+        if not devices: 
+            msg = "WifiPhy not connected to device"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return devices[0]
+
+    @property
+    def channel(self):
+        from nepi.resources.ns3.ns3wifichannel import NS3BaseWifiChannel
+        channels = self.get_connected(NS3BaseWifiChannel.get_rtype())
+
+        if not channels: 
+            msg = "WifiPhy not connected to channel"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return channels[0]
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.device)
+        return rms
+
+    def _connect_object(self):
+        device = self.device
+        if device.uuid not in self.connected:
+            self._connected.add(device.uuid)
+
+            self.simulation.invoke(self.uuid, "SetMobility", self.node.uuid)
+
+            standard = self.get("Standard")
+            self.simulation.invoke(self.uuid, "ConfigureStandard", WIFI_STANDARDS[standard])
+
+            self.simulation.invoke(self.uuid, "SetDevice", device.uuid)
+
+            self.simulation.invoke(self.uuid, "SetChannel", self.channel.uuid)
+            
+            self.simulation.invoke(device.uuid, "SetPhy", self.uuid)
+
diff --git a/src/nepi/resources/ns3/ns3wifiremotestationmanager.py b/src/nepi/resources/ns3/ns3wifiremotestationmanager.py
new file mode 100644 (file)
index 0000000..764c097
--- /dev/null
@@ -0,0 +1,55 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.resource import clsinit_copy
+from nepi.resources.ns3.ns3base import NS3Base
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice
+
+@clsinit_copy
+class NS3BaseWifiRemoteStationManager(NS3Base):
+    _rtype = "abstract::ns3::WifiRemoteStationManager"
+
+    @property
+    def node(self):
+        return self.device.node
+
+    @property
+    def device(self):
+        from nepi.resources.ns3.ns3wifinetdevice import NS3BaseWifiNetDevice
+        devices = self.get_connected(NS3BaseWifiNetDevice.get_rtype())
+
+        if not devices: 
+            msg = "WifiRemoteStationManager not connected to device"
+            self.error(msg)
+            raise RuntimeError, msg
+
+        return devices[0]
+
+    @property
+    def _rms_to_wait(self):
+        rms = set()
+        rms.add(self.device)
+        return rms
+
+    def _connect_object(self):
+        device = self.device
+        if device.uuid not in self.connected:
+            self.simulation.invoke(device.uuid, "SetRemoteStationManager", self.uuid)
+            self._connected.add(device.uuid)
+
index 388fcb7..b617f33 100644 (file)
@@ -21,143 +21,277 @@ import logging
 import os
 import sys
 import threading
+import time
 import uuid
 
+SINGLETON = "singleton::"
+SIMULATOR_UUID = "singleton::Simulator"
+CONFIG_UUID = "singleton::Config"
+GLOBAL_VALUE_UUID = "singleton::GlobalValue"
+IPV4_GLOBAL_ROUTING_HELPER_UUID = "singleton::Ipv4GlobalRoutingHelper"
+
+def load_ns3_libraries():
+    import ctypes
+    import re
+
+    libdir = os.environ.get("NS3LIBRARIES")
+
+    # Load the ns-3 modules shared libraries
+    if libdir:
+        files = os.listdir(libdir)
+        regex = re.compile("(.*\.so)$")
+        libs = [m.group(1) for filename in files for m in [regex.search(filename)] if m]
+
+        initial_size = len(libs)
+        # Try to load the libraries in the right order by trial and error.
+        # Loop until all libraries are loaded.
+        while len(libs) > 0:
+            for lib in libs:
+                libfile = os.path.join(libdir, lib)
+                try:
+                    ctypes.CDLL(libfile, ctypes.RTLD_GLOBAL)
+                    libs.remove(lib)
+                except:
+                    #import traceback
+                    #err = traceback.format_exc()
+                    #print err
+                    pass
+
+            # if did not load any libraries in the last iteration break
+            # to prevent infinit loop
+            if initial_size == len(libs):
+                raise RuntimeError("Imposible to load shared libraries %s" % str(libs))
+            initial_size = len(libs)
+
+def load_ns3_module():
+    load_ns3_libraries()
+
+    # import the python bindings for the ns-3 modules
+    bindings = os.environ.get("NS3BINDINGS")
+    if bindings:
+        sys.path.append(bindings)
+
+    import pkgutil
+    import imp
+    import ns
+
+    # create a Python module to add all ns3 classes
+    ns3mod = imp.new_module("ns3")
+    sys.modules["ns3"] = ns3mod
+
+    for importer, modname, ispkg in pkgutil.iter_modules(ns.__path__):
+        if modname in [ "visualizer" ]:
+            continue
+
+        fullmodname = "ns.%s" % modname
+        module = __import__(fullmodname, globals(), locals(), ['*'])
+
+        for sattr in dir(module):
+            if sattr.startswith("_"):
+                continue
+
+            attr = getattr(module, sattr)
+
+            # netanim.Config and lte.Config singleton overrides ns3::Config
+            if sattr == "Config" and modname in ['netanim', 'lte']:
+                sattr = "%s.%s" % (modname, sattr)
+
+            setattr(ns3mod, sattr, attr)
+
+    return ns3mod
+
 class NS3Wrapper(object):
-    def __init__(self, homedir = None):
+    def __init__(self, loglevel = logging.INFO):
         super(NS3Wrapper, self).__init__()
-        self._ns3 = None
-        self._uuid = self.make_uuid()
-        self._homedir = homedir or os.path.join("/tmp", self._uuid)
+        # Thread used to run the simulation
         self._simulation_thread = None
         self._condition = None
 
+        # True if Simulator::Run was invoked
         self._started = False
-        self._stopped = False
-
-        # holds reference to all ns-3 objects in the simulation
-        self._resources = dict()
 
-        # create home dir (where all simulation related files will end up)
-        home = os.path.normpath(self.homedir)
-        if not os.path.exists(home):
-            os.makedirs(home, 0755)
+        # holds reference to all C++ objects and variables in the simulation
+        self._objects = dict()
 
         # Logging
-        loglevel = os.environ.get("NS3LOGLEVEL", "debug")
-        self._logger = logging.getLogger("ns3wrapper.%s" % self.uuid)
-        self._logger.setLevel(getattr(logging, loglevel.upper()))
-        hdlr = logging.FileHandler(os.path.join(self.homedir, "ns3wrapper.log"))
-        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
-        hdlr.setFormatter(formatter)
-        self._logger.addHandler(hdlr) 
-
-        # Load ns-3 shared libraries and import modules
-        self._load_ns3_module()
-        
+        self._logger = logging.getLogger("ns3wrapper")
+        self._logger.setLevel(loglevel)
+
+        ## NOTE that the reason to create a handler to the ns3 module,
+        # that is re-loaded each time a ns-3 wrapper is instantiated,
+        # is that else each unit test for the ns3wrapper class would need
+        # a separate file. Several ns3wrappers would be created in the 
+        # same unit test (single process), leading to inchorences in the 
+        # state of ns-3 global objects
+        #
+        # Handler to ns3 classes
+        self._ns3 = None
+
+        # Collection of allowed ns3 classes
+        self._allowed_types = None
+
     @property
     def ns3(self):
-        return self._ns3
+        if not self._ns3:
+            # load ns-3 libraries and bindings
+            self._ns3 = load_ns3_module()
 
-    @property
-    def homedir(self):
-        return self._homedir
+        return self._ns3
 
     @property
-    def uuid(self):
-        return self._uuid
+    def allowed_types(self):
+        if not self._allowed_types:
+            self._allowed_types = set()
+            type_id = self.ns3.TypeId()
+            
+            tid_count = type_id.GetRegisteredN()
+            base = type_id.LookupByName("ns3::Object")
+
+            for i in xrange(tid_count):
+                tid = type_id.GetRegistered(i)
+                
+                if tid.MustHideFromDocumentation() or \
+                        not tid.HasConstructor() or \
+                        not tid.IsChildOf(base): 
+                    continue
+
+                type_name = tid.GetName()
+                self._allowed_types.add(type_name)
+        
+        return self._allowed_types
 
     @property
     def logger(self):
         return self._logger
 
+    @property
+    def is_running(self):
+        return self._started and self.ns3.Simulator.IsFinished()
+
     def make_uuid(self):
         return "uuid%s" % uuid.uuid4()
 
-    def singleton(self, clazzname):
-        uuid = "uuid%s"%clazzname
-
-        if not uuid in self._resources:
-            if not hasattr(self.ns3, clazzname):
-                msg = "Type %s not supported" % (typeid) 
-                self.logger.error(msg)
+    def get_object(self, uuid):
+        return self._objects.get(uuid)
 
-            clazz = getattr(self.ns3, clazzname)
-            typeid = "ns3::%s" % clazzname
-            self._resources[uuid] = (clazz, typeid)
+    def factory(self, type_name, **kwargs):
+        if type_name not in self.allowed_types:
+            msg = "Type %s not supported" % (type_name) 
+            self.logger.error(msg)
+        factory = self.ns3.ObjectFactory()
+        factory.SetTypeId(type_name)
 
-        return uuid
+        for name, value in kwargs.iteritems():
+            ns3_value = self._attr_from_string_to_ns3_value(type_name, name, value)
+            factory.Set(name, ns3_value)
 
-    def get_trace(self, trace, offset = None, nbytes = None ):
-        pass
+        obj = factory.Create()
 
-    def is_running(self):
-        return self._started and not self._stopped
+        uuid = self.make_uuid()
+        self._objects[uuid] = obj
 
-    def get_resource(self, uuid):
-        (resource, typeid) =  self._resources.get(uuid)
-        return resource
-    
-    def get_typeid(self, uuid):
-        (resource, typeid) =  self._resources.get(uuid)
-        return typeid
+        return uuid
 
     def create(self, clazzname, *args):
         if not hasattr(self.ns3, clazzname):
             msg = "Type %s not supported" % (clazzname) 
             self.logger.error(msg)
-
+     
         clazz = getattr(self.ns3, clazzname)
-        #typeid = clazz.GetInstanceTypeId().GetName()
-        typeid = "ns3::%s" % clazzname
-
-        realargs = [self.get_resource(arg) if \
-                str(arg).startswith("uuid") else arg for arg in args]
-      
-        resource = clazz(*realargs)
+        # arguments starting with 'uuid' identify ns-3 C++
+        # objects and must be replaced by the actual object
+        realargs = self.replace_args(args)
+       
+        obj = clazz(*realargs)
         
         uuid = self.make_uuid()
-        self._resources[uuid] = (resource, typeid)
+        self._objects[uuid] = obj
+
         return uuid
 
-    def set(self, uuid, name, value):
-        resource = self.get_resource(uuid)
+    def invoke(self, uuid, operation, *args, **kwargs):
+        if operation == "isAppRunning":
+            return self._is_app_running(uuid)
+        if operation == "addStaticRoute":
+            return self._add_static_route(uuid, *args)
 
-        if hasattr(resource, name):
-            setattr(resource, name, value)
+        if uuid.startswith(SINGLETON):
+            obj = self._singleton(uuid)
         else:
-            self._set_ns3_attr(uuid, name, value)
+            obj = self.get_object(uuid)
+        
+        method = getattr(obj, operation)
 
-    def get(self, name, uuid = None):
-        resource = self.get_resource(uuid)
+        # arguments starting with 'uuid' identify ns-3 C++
+        # objects and must be replaced by the actual object
+        realargs = self.replace_args(args)
+        realkwargs = self.replace_kwargs(kwargs)
 
-        value = None
-        if hasattr(resource, name):
-            value = getattr(resource, name)
-        else:
-            value = self._get_ns3_attr(uuid, name)
+        result = method(*realargs, **realkwargs)
+
+        # If the result is not an object, no need to 
+        # keep a reference. Directly return value.
+        if result is None or type(result) in [bool, float, long, str, int]:
+            return result
+      
+        newuuid = self.make_uuid()
+        self._objects[newuuid] = result
+
+        return newuuid
+
+    def _set_attr(self, obj, name, ns3_value):
+        obj.SetAttribute(name, ns3_value)
+
+    def set(self, uuid, name, value):
+        obj = self.get_object(uuid)
+        type_name = obj.GetInstanceTypeId().GetName()
+        ns3_value = self._attr_from_string_to_ns3_value(type_name, name, value)
+
+        # If the Simulation thread is not running,
+        # then there will be no thread-safety problems
+        # in changing the value of an attribute directly.
+        # However, if the simulation is running we need
+        # to set the value by scheduling an event, else
+        # we risk to corrupt the state of the
+        # simulation.
+        
+        event_executed = [False]
+
+        if self.is_running:
+            # schedule the event in the Simulator
+            self._schedule_event(self._condition, event_executed, 
+                    self._set_attr, obj, name, ns3_value)
+
+        if not event_executed[0]:
+            self._set_attr(obj, name, ns3_value)
 
         return value
 
-    def invoke(self, uuid, operation, *args):
-        resource = self.get_resource(uuid)
-        typeid = self.get_typeid(uuid)
-        method = getattr(resource, operation)
+    def _get_attr(self, obj, name, ns3_value):
+        obj.GetAttribute(name, ns3_value)
 
-        realargs = [self.get_resource(arg) if \
-                str(arg).startswith("uuid") else arg for arg in args]
+    def get(self, uuid, name):
+        obj = self.get_object(uuid)
+        type_name = obj.GetInstanceTypeId().GetName()
+        ns3_value = self._create_attr_ns3_value(type_name, name)
 
-        result = method(*realargs)
+        event_executed = [False]
 
-        if not result:
-            return None
-        
-        uuid = self.make_uuid()
-        self._resources[uuid] = (result, typeid)
+        if self.is_running:
+            # schedule the event in the Simulator
+            self._schedule_event(self._condition, event_executed,
+                    self._get_attr, obj, name, ns3_value)
 
-        return uuid
+        if not event_executed[0]:
+            self._get_attr(obj, name, ns3_value)
+
+        return self._attr_from_ns3_value_to_string(type_name, name, ns3_value)
 
     def start(self):
+        # Launch the simulator thread and Start the
+        # simulator in that thread
         self._condition = threading.Condition()
         self._simulator_thread = threading.Thread(
                 target = self._simulator_run,
@@ -167,51 +301,46 @@ class NS3Wrapper(object):
         self._started = True
 
     def stop(self, time = None):
-        if not self.ns3:
-            return
-
         if time is None:
             self.ns3.Simulator.Stop()
         else:
             self.ns3.Simulator.Stop(self.ns3.Time(time))
-        self._stopped = True
 
     def shutdown(self):
-        if self.ns3:
-            if not self.ns3.Simulator.IsFinished():
-                self.stop()
-            
-            # TODO!!!! SHOULD WAIT UNTIL THE THREAD FINISHES
-            if self._simulator_thread:
-                self._simulator_thread.join()
-            
-            self.ns3.Simulator.Destroy()
+        while not self.ns3.Simulator.IsFinished():
+            #self.logger.debug("Waiting for simulation to finish")
+            time.sleep(0.5)
         
-        self._resources.clear()
+        if self._simulator_thread:
+            self._simulator_thread.join()
+       
+        self.ns3.Simulator.Destroy()
+        
+        # Remove all references to ns-3 objects
+        self._objects.clear()
         
-        self._ns3 = None
         sys.stdout.flush()
         sys.stderr.flush()
 
     def _simulator_run(self, condition):
         # Run simulation
         self.ns3.Simulator.Run()
-        # Signal condition on simulation end to notify waiting threads
+        # Signal condition to indicate simulation ended and
+        # notify waiting threads
         condition.acquire()
         condition.notifyAll()
         condition.release()
 
-    def _schedule_event(self, condition, func, *args):
+    def _schedule_event(self, condition, event_executed, func, *args):
         """ Schedules event on running simulation, and wait until
             event is executed"""
 
-        def execute_event(contextId, condition, has_event_occurred, func, *args):
+        def execute_event(contextId, condition, event_executed, func, *args):
             try:
                 func(*args)
+                event_executed[0] = True
             finally:
-                # flag event occured
-                has_event_occurred[0] = True
-                # notify condition indicating attribute was set
+                # notify condition indicating event was executed
                 condition.acquire()
                 condition.notifyAll()
                 condition.release()
@@ -221,71 +350,37 @@ class NS3Wrapper(object):
 
         # delay 0 means that the event is expected to execute inmediately
         delay = self.ns3.Seconds(0)
+    
+        # Mark event as not executed
+        event_executed[0] = False
 
-        # flag to indicate that the event occured
-        # because bool is an inmutable object in python, in order to create a
-        # bool flag, a list is used as wrapper
-        has_event_occurred = [False]
         condition.acquire()
         try:
+            self.ns3.Simulator.ScheduleWithContext(contextId, delay, execute_event, 
+                    condition, event_executed, func, *args)
             if not self.ns3.Simulator.IsFinished():
-                self.ns3.Simulator.ScheduleWithContext(contextId, delay, execute_event,
-                     condition, has_event_occurred, func, *args)
-                while not has_event_occurred[0] and not self.ns3.Simulator.IsFinished():
-                    condition.wait()
+                condition.wait()
         finally:
             condition.release()
 
-    def _set_ns3_attr(self, uuid, name, value):
-        resource = self.get_resource(uuid)
-        ns3_value = self._to_ns3_value(uuid, name, value)
-
-        def set_attr(resource, name, ns3_value):
-            resource.SetAttribute(name, ns3_value)
-
-        if self._is_running:
-            # schedule the event in the Simulator
-            self._schedule_event(self._condition, set_attr, resource,
-                    name, ns3_value)
-        else:
-            set_attr(resource, name, ns3_value)
-
-    def _get_ns3_attr(self, uuid, name):
-        resource = self.get_resource(uuid)
-        ns3_value = self._create_ns3_value(uuid, name)
-
-        def get_attr(resource, name, ns3_value):
-            resource.GetAttribute(name, ns3_value)
-
-        if self._is_running:
-            # schedule the event in the Simulator
-            self._schedule_event(self._condition, get_attr, resource,
-                    name, ns3_value)
-        else:
-            get_attr(resource, name, ns3_value)
-
-        return self._from_ns3_value(uuid, name, ns3_value)
-
-    def _create_ns3_value(self, uuid, name):
-        typeid = get_typeid(uuid)
+    def _create_attr_ns3_value(self, type_name, name):
         TypeId = self.ns3.TypeId()
-        tid = TypeId.LookupByName(typeid)
+        tid = TypeId.LookupByName(type_name)
         info = TypeId.AttributeInformation()
         if not tid.LookupAttributeByName(name, info):
-            msg = "TypeId %s has no attribute %s" % (typeid, name) 
+            msg = "TypeId %s has no attribute %s" % (type_name, name) 
             self.logger.error(msg)
 
         checker = info.checker
         ns3_value = checker.Create() 
         return ns3_value
 
-    def _from_ns3_value(self, uuid, name, ns3_value):
-        typeid = get_typeid(uuid)
+    def _attr_from_ns3_value_to_string(self, type_name, name, ns3_value):
         TypeId = self.ns3.TypeId()
-        tid = TypeId.LookupByName(typeid)
+        tid = TypeId.LookupByName(type_name)
         info = TypeId.AttributeInformation()
         if not tid.LookupAttributeByName(name, info):
-            msg = "TypeId %s has no attribute %s" % (typeid, name) 
+            msg = "TypeId %s has no attribute %s" % (type_name, name) 
             self.logger.error(msg)
 
         checker = info.checker
@@ -301,13 +396,12 @@ class NS3Wrapper(object):
 
         return value
 
-    def _to_ns3_value(self, uuid, name, value):
-        typeid = get_typeid(uuid)
+    def _attr_from_string_to_ns3_value(self, type_name, name, value):
         TypeId = self.ns3.TypeId()
-        typeid = TypeId.LookupByName(typeid)
+        tid = TypeId.LookupByName(type_name)
         info = TypeId.AttributeInformation()
         if not tid.LookupAttributeByName(name, info):
-            msg = "TypeId %s has no attribute %s" % (typeid, name) 
+            msg = "TypeId %s has no attribute %s" % (type_name, name) 
             self.logger.error(msg)
 
         str_value = str(value)
@@ -319,62 +413,105 @@ class NS3Wrapper(object):
         ns3_value.DeserializeFromString(str_value, checker)
         return ns3_value
 
-    def _load_ns3_module(self):
-        if self.ns3:
-            return 
-
-        import ctypes
-        import imp
-        import re
-        import pkgutil
-
-        bindings = os.environ.get("NS3BINDINGS")
-        libdir = os.environ.get("NS3LIBRARIES")
-
-        # Load the ns-3 modules shared libraries
-        if libdir:
-            files = os.listdir(libdir)
-            regex = re.compile("(.*\.so)$")
-            libs = [m.group(1) for filename in files for m in [regex.search(filename)] if m]
-
-            libscp = list(libs)
-            while len(libs) > 0:
-                for lib in libs:
-                    libfile = os.path.join(libdir, lib)
-                    try:
-                        ctypes.CDLL(libfile, ctypes.RTLD_GLOBAL)
-                        libs.remove(lib)
-                    except:
-                        pass
-
-                # if did not load any libraries in the last iteration break
-                # to prevent infinit loop
-                if len(libscp) == len(libs):
-                    raise RuntimeError("Imposible to load shared libraries %s" % str(libs))
-                libscp = list(libs)
-
-        # import the python bindings for the ns-3 modules
-        if bindings:
-            sys.path.append(bindings)
-
-        # create a module to add all ns3 classes
-        ns3mod = imp.new_module("ns3")
-        sys.modules["ns3"] = ns3mod
-
-        # retrieve all ns3 classes and add them to the ns3 module
-        import ns
-        for importer, modname, ispkg in pkgutil.iter_modules(ns.__path__):
-            fullmodname = "ns.%s" % modname
-            module = __import__(fullmodname, globals(), locals(), ['*'])
-
-            # netanim.Config singleton overrides ns3::Config
-            if modname in ['netanim']:
-                continue
+    # singletons are identified as "ns3::ClassName"
+    def _singleton(self, ident):
+        if not ident.startswith(SINGLETON):
+            return None
 
-            for sattr in dir(module):
-                if not sattr.startswith("_"):
-                    attr = getattr(module, sattr)
-                    setattr(ns3mod, sattr, attr)
+        clazzname = ident[ident.find("::")+2:]
+        if not hasattr(self.ns3, clazzname):
+            msg = "Type %s not supported" % (clazzname)
+            self.logger.error(msg)
 
-        self._ns3 = ns3mod
+        return getattr(self.ns3, clazzname)
+
+    # replace uuids and singleton references for the real objects
+    def replace_args(self, args):
+        realargs = [self.get_object(arg) if \
+                str(arg).startswith("uuid") else arg for arg in args]
+        realargs = [self._singleton(arg) if \
+                str(arg).startswith(SINGLETON) else arg for arg in realargs]
+
+        return realargs
+
+    # replace uuids and singleton references for the real objects
+    def replace_kwargs(self, kwargs):
+        realkwargs = dict([(k, self.get_object(v) \
+                if str(v).startswith("uuid") else v) \
+                for k,v in kwargs.iteritems()])
+        realkwargs = dict([(k, self._singleton(v) \
+                if str(v).startswith(SINGLETON) else v )\
+                for k, v in realkwargs.iteritems()])
+
+        return realkwargs
+
+    def _is_app_running(self, uuid): 
+        now = self.ns3.Simulator.Now()
+        if now.IsZero():
+            return False
+
+        app = self.get_object(uuid)
+        stop_time_value = self.ns3.TimeValue()
+        app.GetAttribute("StopTime", stop_time_value)
+        stop_time = stop_time_value.Get()
+
+        start_time_value = self.ns3.TimeValue()
+        app.GetAttribute("StartTime", start_time_value)
+        start_time = start_time_value.Get()
+        
+        if now.Compare(start_time) >= 0 and now.Compare(stop_time) < 0:
+            return True
+
+        return False
+
+    def _add_static_route(self, ipv4_uuid, network, prefix, nexthop):
+        ipv4 = self.get_object(ipv4_uuid)
+
+        list_routing = ipv4.GetRoutingProtocol()
+        (static_routing, priority) = list_routing.GetRoutingProtocol(0)
+
+        ifindex = self._find_ifindex(ipv4, nexthop)
+        if ifindex == -1:
+            return False
+        
+        nexthop = self.ns3.Ipv4Address(nexthop)
+
+        if network in ["0.0.0.0", "0", None]:
+            # Default route: 0.0.0.0/0
+            static_routing.SetDefaultRoute(nexthop, ifindex)
+        else:
+            mask = self.ns3.Ipv4Mask("/%s" % prefix) 
+            network = self.ns3.Ipv4Address(network)
+
+            if prefix == 32:
+                # Host route: x.y.z.w/32
+                static_routing.AddHostRouteTo(network, nexthop, ifindex)
+            else:
+                # Network route: x.y.z.w/n
+                static_routing.AddNetworkRouteTo(network, mask, nexthop, 
+                        ifindex) 
+        return True
+
+    def _find_ifindex(self, ipv4, nexthop):
+        ifindex = -1
+
+        nexthop = self.ns3.Ipv4Address(nexthop)
+
+        # For all the interfaces registered with the ipv4 object, find
+        # the one that matches the network of the nexthop
+        nifaces = ipv4.GetNInterfaces()
+        for ifidx in xrange(nifaces):
+            iface = ipv4.GetInterface(ifidx)
+            naddress = iface.GetNAddresses()
+            for addridx in xrange(naddress):
+                ifaddr = iface.GetAddress(addridx)
+                ifmask = ifaddr.GetMask()
+                
+                ifindex = ipv4.GetInterfaceForPrefix(nexthop, ifmask)
+
+                if ifindex == ifidx:
+                    return ifindex
+        return ifindex
 
diff --git a/src/nepi/resources/ns3/ns3wrapper_server.py b/src/nepi/resources/ns3/ns3wrapper_server.py
deleted file mode 100644 (file)
index 2773948..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-#
-#    NEPI, a framework to manage network experiments
-#    Copyright (C) 2013 INRIA
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-
-
-class Server(object):
-    def __init__(self, root_dir = ".", log_level = "ERROR", 
-            environment_setup = "", clean_root = False):
-        self._root_dir = root_dir
-        self._clean_root = clean_root
-        self._stop = False
-        self._ctrl_sock = None
-        self._log_level = log_level
-        self._rdbuf = ""
-        self._environment_setup = environment_setup
-
-    def run(self):
-        try:
-            if self.daemonize():
-                self.post_daemonize()
-                self.loop()
-                self.cleanup()
-                # ref: "os._exit(0)"
-                # can not return normally after fork beacuse no exec was done.
-                # This means that if we don't do a os._exit(0) here the code that 
-                # follows the call to "Server.run()" in the "caller code" will be 
-                # executed... but by now it has already been executed after the 
-                # first process (the one that did the first fork) returned.
-                os._exit(0)
-        except:
-            print >>sys.stderr, "SERVER_ERROR."
-            self.log_error()
-            self.cleanup()
-            os._exit(0)
-        print >>sys.stderr, "SERVER_READY."
-
-    def daemonize(self):
-        # pipes for process synchronization
-        (r, w) = os.pipe()
-        
-        # build root folder
-        root = os.path.normpath(self._root_dir)
-        if self._root_dir not in [".", ""] and os.path.exists(root) \
-                and self._clean_root:
-            shutil.rmtree(root)
-        if not os.path.exists(root):
-            os.makedirs(root, 0755)
-
-        pid1 = os.fork()
-        if pid1 > 0:
-            os.close(w)
-            while True:
-                try:
-                    os.read(r, 1)
-                except OSError, e: # pragma: no cover
-                    if e.errno == errno.EINTR:
-                        continue
-                    else:
-                        raise
-                break
-            os.close(r)
-            # os.waitpid avoids leaving a <defunc> (zombie) process
-            st = os.waitpid(pid1, 0)[1]
-            if st:
-                raise RuntimeError("Daemonization failed")
-            # return 0 to inform the caller method that this is not the 
-            # daemonized process
-            return 0
-        os.close(r)
-
-        # Decouple from parent environment.
-        os.chdir(self._root_dir)
-        os.umask(0)
-        os.setsid()
-
-        # fork 2
-        pid2 = os.fork()
-        if pid2 > 0:
-            # see ref: "os._exit(0)"
-            os._exit(0)
-
-        # close all open file descriptors.
-        max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
-        if (max_fd == resource.RLIM_INFINITY):
-            max_fd = MAX_FD
-        for fd in range(3, max_fd):
-            if fd != w:
-                try:
-                    os.close(fd)
-                except OSError:
-                    pass
-
-        # Redirect standard file descriptors.
-        stdin = open(DEV_NULL, "r")
-        stderr = stdout = open(STD_ERR, "a", 0)
-        os.dup2(stdin.fileno(), sys.stdin.fileno())
-        # NOTE: sys.stdout.write will still be buffered, even if the file
-        # was opened with 0 buffer
-        os.dup2(stdout.fileno(), sys.stdout.fileno())
-        os.dup2(stderr.fileno(), sys.stderr.fileno())
-        
-        # setup environment
-        if self._environment_setup:
-            # parse environment variables and pass to child process
-            # do it by executing shell commands, in case there's some heavy setup involved
-            envproc = subprocess.Popen(
-                [ "bash", "-c", 
-                    "( %s python -c 'import os,sys ; print \"\\x01\".join(\"\\x02\".join(map(str,x)) for x in os.environ.iteritems())' ) | tail -1" %
-                        ( self._environment_setup, ) ],
-                stdin = subprocess.PIPE, 
-                stdout = subprocess.PIPE,
-                stderr = subprocess.PIPE
-            )
-            out,err = envproc.communicate()
-
-            # parse new environment
-            if out:
-                environment = dict(map(lambda x:x.split("\x02"), out.split("\x01")))
-            
-                # apply to current environment
-                for name, value in environment.iteritems():
-                    os.environ[name] = value
-                
-                # apply pythonpath
-                if 'PYTHONPATH' in environment:
-                    sys.path = environment['PYTHONPATH'].split(':') + sys.path
-
-        # create control socket
-        self._ctrl_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        try:
-            self._ctrl_sock.bind(CTRL_SOCK)
-        except socket.error:
-            # Address in use, check pidfile
-            pid = None
-            try:
-                pidfile = open(CTRL_PID, "r")
-                pid = pidfile.read()
-                pidfile.close()
-                pid = int(pid)
-            except:
-                # no pidfile
-                pass
-            
-            if pid is not None:
-                # Check process liveliness
-                if not os.path.exists("/proc/%d" % (pid,)):
-                    # Ok, it's dead, clean the socket
-                    os.remove(CTRL_SOCK)
-            
-            # try again
-            self._ctrl_sock.bind(CTRL_SOCK)
-            
-        self._ctrl_sock.listen(0)
-        
-        # Save pidfile
-        pidfile = open(CTRL_PID, "w")
-        pidfile.write(str(os.getpid()))
-        pidfile.close()
-
-        # let the parent process know that the daemonization is finished
-        os.write(w, "\n")
-        os.close(w)
-        return 1
-
-    def post_daemonize(self):
-        os.environ["NEPI_CONTROLLER_LOGLEVEL"] = self._log_level
-        # QT, for some strange reason, redefines the SIGCHILD handler to write
-        # a \0 to a fd (lets say fileno 'x'), when ever a SIGCHILD is received.
-        # Server dameonization closes all file descriptors from fileno '3',
-        # but the overloaded handler (inherited by the forked process) will
-        # keep trying to write the \0 to fileno 'x', which might have been reused 
-        # after closing, for other operations. This is bad bad bad when fileno 'x'
-        # is in use for communication pouroses, because unexpected \0 start
-        # appearing in the communication messages... this is exactly what happens 
-        # when using netns in daemonized form. Thus, be have no other alternative than
-        # restoring the SIGCHLD handler to the default here.
-        import signal
-        signal.signal(signal.SIGCHLD, signal.SIG_DFL)
-
-    def loop(self):
-        while not self._stop:
-            conn, addr = self._ctrl_sock.accept()
-            self.log_error("ACCEPTED CONNECTION: %s" % (addr,))
-            conn.settimeout(5)
-            while not self._stop:
-                try:
-                    msg = self.recv_msg(conn)
-                except socket.timeout, e:
-                    #self.log_error("SERVER recv_msg: connection timedout ")
-                    continue
-                
-                if not msg:
-                    self.log_error("CONNECTION LOST")
-                    break
-                    
-                if msg == STOP_MSG:
-                    self._stop = True
-                    reply = self.stop_action()
-                else:
-                    reply = self.reply_action(msg)
-                
-                try:
-                    self.send_reply(conn, reply)
-                except socket.error:
-                    self.log_error()
-                    self.log_error("NOTICE: Awaiting for reconnection")
-                    break
-            try:
-                conn.close()
-            except:
-                # Doesn't matter
-                self.log_error()
-
-    def recv_msg(self, conn):
-        data = [self._rdbuf]
-        chunk = data[0]
-        while '\n' not in chunk:
-            try:
-                chunk = conn.recv(1024)
-            except (OSError, socket.error), e:
-                if e[0] != errno.EINTR:
-                    raise
-                else:
-                    continue
-            if chunk:
-                data.append(chunk)
-            else:
-                # empty chunk = EOF
-                break
-        data = ''.join(data).split('\n',1)
-        while len(data) < 2:
-            data.append('')
-        data, self._rdbuf = data
-        
-        decoded = base64.b64decode(data)
-        return decoded.rstrip()
-
-    def send_reply(self, conn, reply):
-        encoded = base64.b64encode(reply)
-        conn.send("%s\n" % encoded)
-       
-    def cleanup(self):
-        try:
-            self._ctrl_sock.close()
-            os.remove(CTRL_SOCK)
-        except:
-            self.log_error()
-
-    def stop_action(self):
-        return "Stopping server"
-
-    def reply_action(self, msg):
-        return "Reply to: %s" % msg
-
-    def log_error(self, text = None, context = ''):
-        if text == None:
-            text = traceback.format_exc()
-        date = time.strftime("%Y-%m-%d %H:%M:%S")
-        if context:
-            context = " (%s)" % (context,)
-        sys.stderr.write("ERROR%s: %s\n%s\n" % (context, date, text))
-        return text
-
-    def log_debug(self, text):
-        if self._log_level == DC.DEBUG_LEVEL:
-            date = time.strftime("%Y-%m-%d %H:%M:%S")
-            sys.stderr.write("DEBUG: %s\n%s\n" % (date, text))
-
-class Forwarder(object):
-    def __init__(self, root_dir = "."):
-        self._ctrl_sock = None
-        self._root_dir = root_dir
-        self._stop = False
-        self._rdbuf = ""
-
-    def forward(self):
-        self.connect()
-        print >>sys.stderr, "FORWARDER_READY."
-        while not self._stop:
-            data = self.read_data()
-            if not data:
-                # Connection to client lost
-                break
-            self.send_to_server(data)
-            
-            data = self.recv_from_server()
-            if not data:
-                # Connection to server lost
-                raise IOError, "Connection to server lost while "\
-                    "expecting response"
-            self.write_data(data)
-        self.disconnect()
-
-    def read_data(self):
-        return sys.stdin.readline()
-
-    def write_data(self, data):
-        sys.stdout.write(data)
-        # sys.stdout.write is buffered, this is why we need to do a flush()
-        sys.stdout.flush()
-
-    def send_to_server(self, data):
-        try:
-            self._ctrl_sock.send(data)
-        except (IOError, socket.error), e:
-            if e[0] == errno.EPIPE:
-                self.connect()
-                self._ctrl_sock.send(data)
-            else:
-                raise e
-        encoded = data.rstrip() 
-        msg = base64.b64decode(encoded)
-        if msg == STOP_MSG:
-            self._stop = True
-
-    def recv_from_server(self):
-        data = [self._rdbuf]
-        chunk = data[0]
-        while '\n' not in chunk:
-            try:
-                chunk = self._ctrl_sock.recv(1024)
-            except (OSError, socket.error), e:
-                if e[0] != errno.EINTR:
-                    raise
-                continue
-            if chunk:
-                data.append(chunk)
-            else:
-                # empty chunk = EOF
-                break
-        data = ''.join(data).split('\n',1)
-        while len(data) < 2:
-            data.append('')
-        data, self._rdbuf = data
-        
-        return data+'\n'
-    def connect(self):
-        self.disconnect()
-        self._ctrl_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        sock_addr = os.path.join(self._root_dir, CTRL_SOCK)
-        self._ctrl_sock.connect(sock_addr)
-
-    def disconnect(self):
-        try:
-            self._ctrl_sock.close()
-        except:
-            pass
-
diff --git a/src/nepi/resources/ns3/resource_manager_generator.py b/src/nepi/resources/ns3/resource_manager_generator.py
new file mode 100644 (file)
index 0000000..5eae3c8
--- /dev/null
@@ -0,0 +1,225 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+# Force the load of ns3 libraries
+from nepi.resources.ns3.ns3wrapper import load_ns3_module
+
+import os
+import re
+
+adapted_types = ["ns3::Node",
+        "ns3::Application", 
+        #"ns3::DceApplication", 
+        "ns3::NetDevice",
+        "ns3::Channel",
+        "ns3::Queue",
+        "ns3::Icmpv4L4Protocol",
+        "ns3::ArpL3Protocol",
+        "ns3::Ipv4L3Protocol",
+        "ns3::PropagationLossModel",
+        "ns3::MobilityModel",
+        "ns3::PropagationDelayModel",
+        "ns3::WifiRemoteStationManager",
+        "ns3::WifiNetDevice",
+        "ns3::WifiChannel",
+        "ns3::WifiPhy",
+        "ns3::WifiMac",
+        "ns3::ErrorModel",
+        "ns3::ErrorRateModel"]
+
+base_types = ["ns3::IpL4Protocol"]
+
+def select_base_class(ns3, tid): 
+    base_class_import = None
+    base_class = None
+   
+    rtype = tid.GetName()
+
+    type_id = ns3.TypeId()
+
+    for type_name in adapted_types:
+        tid_base = type_id.LookupByName(type_name)
+        if type_name == rtype or tid.IsChildOf(tid_base):
+            base_class = "NS3Base" + type_name.replace("ns3::", "")
+            base_module = "ns3" + type_name.replace("ns3::", "").lower()
+            base_class_import = "from nepi.resources.ns3.%s import %s " % (
+                    base_module, base_class)
+            return (base_class_import, base_class)
+
+    base_class_import = "from nepi.resources.ns3.ns3base import NS3Base"
+    base_class = "NS3Base"
+
+    for type_name in base_types:
+        tid_base = type_id.LookupByName(type_name)
+        if type_name == rtype or tid.IsChildOf(tid_base):
+            return (base_class_import, base_class)
+
+    return (None, None)
+
+def create_ns3_rms():
+    ns3 = load_ns3_module()
+
+    type_id = ns3.TypeId()
+    
+    tid_count = type_id.GetRegisteredN()
+    base = type_id.LookupByName("ns3::Object")
+
+    # Create a .py file using the ns-3 RM template for each ns-3 TypeId
+    for i in xrange(tid_count):
+        tid = type_id.GetRegistered(i)
+        
+        (base_class_import, base_class) = select_base_class(ns3, tid)
+        if not base_class:
+            continue
+        
+        if tid.MustHideFromDocumentation() or \
+                not tid.HasConstructor() or \
+                not tid.IsChildOf(base): 
+            continue
+       
+        attributes = template_attributes(ns3, tid)
+        traces = template_traces(ns3, tid)
+        ptid = tid
+        while ptid.HasParent():
+            ptid = ptid.GetParent()
+            attributes += template_attributes(ns3, ptid)
+            traces += template_traces(ns3, ptid)
+
+        attributes = "\n" + attributes if attributes else "pass"
+        traces = "\n" + traces if traces else "pass"
+
+        category = tid.GetGroupName()
+
+        rtype = tid.GetName()
+        classname = rtype.replace("ns3::", "NS3").replace("::","")
+        uncamm_rtype = re.sub('([a-z])([A-Z])', r'\1-\2', rtype).lower()
+        short_rtype = uncamm_rtype.replace("::","-")
+
+        d = os.path.dirname(os.path.realpath(__file__))
+        ftemp = open(os.path.join(d, "templates", "resource_manager_template.txt"), "r")
+        template = ftemp.read()
+        ftemp.close()
+
+        template = template. \
+                replace("<CLASS_NAME>", classname). \
+                replace("<RTYPE>", rtype). \
+                replace("<ATTRIBUTES>", attributes). \
+                replace("<TRACES>", traces). \
+                replace("<BASE_CLASS_IMPORT>", base_class_import). \
+                replace("<BASE_CLASS>", base_class). \
+                replace("<SHORT-RTYPE>", short_rtype)
+
+        fname = uncamm_rtype.replace('ns3::', ''). \
+                replace('::', ''). \
+                replace("-","_").lower() + ".py"
+
+        f = open(os.path.join(d, "classes", fname), "w")
+        print os.path.join(d, fname)
+        print template
+        f.write(template)
+        f.close()
+
+def template_attributes(ns3, tid): 
+    d = os.path.dirname(os.path.realpath(__file__))
+    ftemp = open(os.path.join(d, "templates", "attribute_template.txt"), "r")
+    template = ftemp.read()
+    ftemp.close()
+
+    attributes = ""
+
+    attr_count = tid.GetAttributeN()
+    for i in xrange(attr_count):
+        attr_info = tid.GetAttribute(i)
+        if not attr_info.accessor.HasGetter():
+            continue
+
+        attr_flags = "Flags.Reserved"
+        flags = attr_info.flags
+        if (flags & ns3.TypeId.ATTR_CONSTRUCT) == ns3.TypeId.ATTR_CONSTRUCT:
+            attr_flags += " | Flags.Construct"
+        else:
+            if (flags & ns3.TypeId.ATTR_GET) != ns3.TypeId.ATTR_GET:
+                attr_flags += " | Flags.NoRead"
+            elif (flags & ns3.TypeId.ATTR_SET) != ns3.TypeId.ATTR_SET:
+                attr_flags += " | Flags.NoWrite"
+
+        attr_name = attr_info.name
+        checker = attr_info.checker
+        attr_help = attr_info.help.replace('"', '\\"').replace("'", "\\'")
+        value = attr_info.initialValue
+        attr_value = value.SerializeToString(checker)
+        attr_allowed = "None"
+        attr_range = "None"
+        attr_type = "Types.String"
+
+        if isinstance(value, ns3.ObjectVectorValue):
+            continue
+        elif isinstance(value, ns3.PointerValue):
+            continue
+        elif isinstance(value, ns3.WaypointValue):
+            continue
+        elif isinstance(value, ns3.BooleanValue):
+            attr_type = "Types.Bool"
+            attr_value = "True" if attr_value == "true" else "False"
+        elif isinstance(value, ns3.EnumValue):
+            attr_type = "Types.Enumerate"
+            allowed = checker.GetUnderlyingTypeInformation().split("|")
+            attr_allowed = "[%s]" % ",".join(map(lambda x: "\"%s\"" % x, allowed))
+        elif isinstance(value, ns3.DoubleValue):
+            attr_type = "Types.Double"
+            # TODO: range
+        elif isinstance(value, ns3.UintegerValue):
+            attr_type = "Types.Integer"
+            # TODO: range
+
+        attr_id = "attr_" + attr_name.lower().replace("-", "_")
+        attributes += template.replace("<ATTR_ID>", attr_id) \
+                .replace("<ATTR_NAME>", attr_name) \
+                .replace("<ATTR_HELP>", attr_help) \
+                .replace("<ATTR_TYPE>", attr_type) \
+                .replace("<ATTR_DEFAULT>", attr_value) \
+                .replace("<ATTR_ALLOWED>", attr_allowed) \
+                .replace("<ATTR_RANGE>", attr_range) \
+                .replace("<ATTR_FLAGS>", attr_flags) 
+
+    return attributes
+
+def template_traces(ns3, tid): 
+    d = os.path.dirname(os.path.realpath(__file__))
+    ftemp = open(os.path.join(d, "templates", "trace_template.txt"), "r")
+    template = ftemp.read()
+    ftemp.close()
+
+    traces = ""
+
+    trace_count = tid.GetTraceSourceN()
+    for i in xrange(trace_count):
+        trace_info = tid.GetTraceSource(i)
+        trace_name = trace_info.name
+        trace_help = trace_info.help.replace('"', '\\"').replace("'", "\\'")
+
+        trace_id = trace_name.lower()
+        traces += template.replace("<TRACE_ID>", trace_id) \
+                .replace("<TRACE_NAME>", trace_name) \
+                .replace("<TRACE_HELP>", trace_help) 
+
+    return traces
+
+if __name__ == "__main__":
+    create_ns3_rms()
diff --git a/src/nepi/resources/ns3/templates/attribute_template.txt b/src/nepi/resources/ns3/templates/attribute_template.txt
new file mode 100644 (file)
index 0000000..651496e
--- /dev/null
@@ -0,0 +1,10 @@
+        <ATTR_ID> = Attribute("<ATTR_NAME>",
+            "<ATTR_HELP>",
+            type = <ATTR_TYPE>,
+            default = "<ATTR_DEFAULT>",  
+            allowed = <ATTR_ALLOWED>,
+            range = <ATTR_RANGE>,    
+            flags = <ATTR_FLAGS>)
+
+        cls._register_attribute(<ATTR_ID>)
+
diff --git a/src/nepi/resources/ns3/templates/resource_manager_template.txt b/src/nepi/resources/ns3/templates/resource_manager_template.txt
new file mode 100644 (file)
index 0000000..c3b6a58
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2014 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay
+<BASE_CLASS_IMPORT>
+
+@clsinit_copy
+class <CLASS_NAME>(<BASE_CLASS>):
+    _rtype = "<RTYPE>"
+
+    @classmethod
+    def _register_attributes(cls):
+        <ATTRIBUTES>
+
+    @classmethod
+    def _register_traces(cls):
+        <TRACES>
+
+    def __init__(self, ec, guid):
+        super(<CLASS_NAME>, self).__init__(ec, guid)
+        self._home = "<SHORT-RTYPE>-%s" % self.guid
diff --git a/src/nepi/resources/ns3/templates/trace_template.txt b/src/nepi/resources/ns3/templates/trace_template.txt
new file mode 100644 (file)
index 0000000..9cedb1e
--- /dev/null
@@ -0,0 +1,4 @@
+        <TRACE_ID> = Trace("<TRACE_NAME>", "<TRACE_HELP>")
+
+        cls._register_trace(<TRACE_ID>)
+
index bc4d0e7..8ef2b50 100644 (file)
@@ -52,11 +52,11 @@ class OMFApplication(OMFResource):
         env = Attribute("env", "Environnement variable of the application")
         stdin = Attribute("stdin", "Input of the application", default = "")
         sources = Attribute("sources", "Sources of the application", 
-                     flags = Flags.ExecReadOnly)
+                     flags = Flags.Design)
         sshuser = Attribute("sshUser", "user to connect with ssh", 
-                     flags = Flags.ExecReadOnly)
+                     flags = Flags.Design)
         sshkey = Attribute("sshKey", "key to use for ssh", 
-                     flags = Flags.ExecReadOnly)
+                     flags = Flags.Design)
         cls._register_attribute(appid)
         cls._register_attribute(path)
         cls._register_attribute(args)
index 1fcd59b..c78daa0 100644 (file)
@@ -180,16 +180,20 @@ class OMFWifiInterface(OMFResource):
             raise RuntimeError, msg
 
         # Just for information
-        self.debug(" " + self.get_rtype() + " ( Guid : " + str(self._guid) +") : " + \
-            self.get('mode') + " : " + self.get('type') + " : " + \
-            self.get('essid') + " : " + self.get('ip'))
+        self.info(" " + self.get_rtype() + " ( Guid : " + str(self._guid) +") : " + \
+                self.get('mode') + " : " + self.get('type') + " : " + \
+                self.get('essid') + " : " + self.get('ip') + " : " + str(self.state))
     
         # Check if the node is already deployed
         if self.state < ResourceState.PROVISIONED:
             if self._conf == False:
                 self._conf = self.configure_iface()
+        res = False
         if self._conf == True:
-            self.configure_ip()
+            res = self.configure_ip()
+            
+        if not (res and self._conf):
+            return
 
         super(OMFWifiInterface, self).do_deploy()
 
index 5def17b..edd1397 100644 (file)
@@ -236,6 +236,7 @@ class OMFAPI(Logger):
         :type value: str
 
         """
+        
         payload = self._message.configure_function(hostname, value, attribute)
         xmpp_node =  self._host_session_id(hostname)
         self._client.publish(payload, xmpp_node)
index 396e2d7..05af4f1 100644 (file)
 
 from nepi.util.logger import Logger
 
-
 try:
     import sleekxmpp
     from sleekxmpp.exceptions import IqError, IqTimeout
     class BaseOMFClient(sleekxmpp.ClientXMPP):
         pass
 except ImportError:
-    print "SleekXMPP is not installed. Without this library, \n" + \
-          " You will be not able to use OMF Resources \n"+ \
-          " If you want to install SleekXmpp : \n"+ \
-          " git clone -b develop git://github.com/fritzy/SleekXMPP.git \n"+ \
-          " cd SleekXMPP \n"+ \
-           "sudo python setup.py install\n"
+    msg = ("SleekXMPP is not installed. Without this library "
+          "you will be not able to use OMF Resources "
+          "if you want to install SleekXmpp: \n"
+          " git clone -b develop git://github.com/fritzy/SleekXMPP.git \n"
+          " cd SleekXMPP \n"
+          " sudo python setup.py install\n")
+
+    logger = Logger("BaseOMFClient")
+    logger.debug(msg)
+
     class BaseOMFClient(object):
         pass
 
@@ -40,7 +43,7 @@ import traceback
 import xml.etree.ElementTree as ET
 
 # inherit from BaseXmpp and XMLstream classes
-class OMFClient(sleekxmpp.ClientXMPP, Logger): 
+class OMFClient(BaseOMFClient, Logger): 
     """
     .. class:: Class Args :
       
index 330ad64..1f706a8 100644 (file)
@@ -27,10 +27,12 @@ from nepi.util.execfuncs import lexec
 from nepi.util import sshfuncs
 
 from random import randint
+import re
 import time
 import socket
 import threading
 import datetime
+import weakref
 
 @clsinit_copy
 class PlanetlabNode(LinuxNode):
@@ -44,7 +46,7 @@ class PlanetlabNode(LinuxNode):
     @classmethod
     def _register_attributes(cls):
         ip = Attribute("ip", "PlanetLab host public IP address",
-                flags = Flags.ReadOnly)
+                    flags = Flags.Design)
 
         pl_url = Attribute("plcApiUrl", "URL of PlanetLab PLCAPI host \
                     (e.g. www.planet-lab.eu or www.planet-lab.org) ",
@@ -54,7 +56,7 @@ class PlanetlabNode(LinuxNode):
         pl_ptn = Attribute("plcApiPattern", "PLC API service regexp pattern \
                     (e.g. https://%(hostname)s:443/PLCAPI/ ) ",
                     default = "https://%(hostname)s:443/PLCAPI/",
-                    flags = Flags.ExecReadOnly)
+                    flags = Flags.Design)
     
         pl_user = Attribute("pluser", "PlanetLab account user, as the one to \
                     authenticate in the website) ",
@@ -94,14 +96,6 @@ class PlanetlabNode(LinuxNode):
                                         "other"],
                             flags = Flags.Filter)
 
-        #site = Attribute("site", "Constrain the PlanetLab site this node \
-        #        should reside on.",
-        #        type = Types.Enumerate,
-        #        allowed = ["PLE",
-        #                    "PLC",
-        #                    "PLJ"],
-        #        flags = Flags.Filter)
-
         min_reliability = Attribute("minReliability", "Constrain reliability \
                             while picking PlanetLab nodes. Specifies a lower \
                             acceptable bound.",
@@ -169,12 +163,20 @@ class PlanetlabNode(LinuxNode):
                                     "year"],
                         flags = Flags.Filter)
 
+        plblacklist = Attribute("persist_blacklist", "Take into account the file plblacklist \
+                        in the user's home directory under .nepi directory. This file \
+                        contains a list of PL nodes to blacklist, and at the end \
+                        of the experiment execution the new blacklisted nodes are added.",
+                    type = Types.Bool,
+                    default = False,
+                    flags = Flags.Global)
+
+
         cls._register_attribute(ip)
         cls._register_attribute(pl_url)
         cls._register_attribute(pl_ptn)
         cls._register_attribute(pl_user)
         cls._register_attribute(pl_password)
-        #cls._register_attribute(site)
         cls._register_attribute(city)
         cls._register_attribute(country)
         cls._register_attribute(region)
@@ -189,10 +191,12 @@ class PlanetlabNode(LinuxNode):
         cls._register_attribute(min_cpu)
         cls._register_attribute(max_cpu)
         cls._register_attribute(timeframe)
+        cls._register_attribute(plblacklist)
 
     def __init__(self, ec, guid):
         super(PlanetlabNode, self).__init__(ec, guid)
 
+        self._ecobj = weakref.ref(ec)
         self._plapi = None
         self._node_to_provision = None
         self._slicenode = False
@@ -216,14 +220,15 @@ class PlanetlabNode(LinuxNode):
             pl_pass = self.get("plpassword")
             pl_url = self.get("plcApiUrl")
             pl_ptn = self.get("plcApiPattern")
-
-            self._plapi =  PLCAPIFactory.get_api(pl_user, pl_pass, pl_url,
-                pl_ptn)
+            _plapi = PLCAPIFactory.get_api(pl_user, pl_pass, pl_url,
+                pl_ptn, self._ecobj())
             
-            if not self._plapi:
+            if not _plapi:
                 self.fail_plapi()
+        
+            self._plapi = weakref.ref(_plapi)
 
-        return self._plapi
+        return self._plapi()
 
     def do_discover(self):
         """
@@ -315,7 +320,15 @@ class PlanetlabNode(LinuxNode):
             node = self._node_to_provision
             if not self._slicenode:
                 self._add_node_to_slice(node)
-            
+                if self._check_if_in_slice([node]):
+                    self.debug( "Node added to slice" )
+                else:
+                    self.warning(" Could not add to slice ")
+                    with PlanetlabNode.lock:
+                        self._blacklist_node(node)
+                    self.do_discover()
+                    continue
+
                 # check ssh connection
                 t = 0 
                 while t < timeout and not ssh_ok:
@@ -323,10 +336,12 @@ class PlanetlabNode(LinuxNode):
                     cmd = 'echo \'GOOD NODE\''
                     ((out, err), proc) = self.execute(cmd)
                     if out.find("GOOD NODE") < 0:
+                        self.debug( "No SSH connection, waiting 60s" )
                         t = t + 60
                         time.sleep(60)
                         continue
                     else:
+                        self.debug( "SSH OK" )
                         ssh_ok = True
                         continue
             else:
@@ -340,7 +355,7 @@ class PlanetlabNode(LinuxNode):
                 # the node is blacklisted, deleted from the slice, and a new
                 # node to provision is discovered
                 with PlanetlabNode.lock:
-                    self.warn(" Could not SSH login ")
+                    self.warning(" Could not SSH login ")
                     self._blacklist_node(node)
                     #self._delete_node_from_slice(node)
                 self.do_discover()
@@ -356,7 +371,7 @@ class PlanetlabNode(LinuxNode):
                 if out1.find("/proc type proc") < 0 or \
                     "Read-only file system".lower() in err2.lower():
                     with PlanetlabNode.lock:
-                        self.warn(" Corrupted file system ")
+                        self.warning(" Corrupted file system ")
                         self._blacklist_node(node)
                         #self._delete_node_from_slice(node)
                     self.do_discover()
@@ -369,9 +384,16 @@ class PlanetlabNode(LinuxNode):
                     # set IP attribute
                     ip = self._get_ip(node)
                     self.set("ip", ip)
+                    self.info(" Node provisioned ")            
             
         super(PlanetlabNode, self).do_provision()
 
+    def do_release(self):
+        super(PlanetlabNode, self).do_release()
+        if self.state == ResourceState.RELEASED:
+            self.debug(" Releasing PLC API ")
+            self.plapi.release()
+
     def _filter_based_on_attributes(self):
         """
         Retrive the list of nodes ids that match user's constraints 
@@ -384,7 +406,6 @@ class PlanetlabNode(LinuxNode):
             'region' : 'region',
             'architecture' : 'arch',
             'operatingSystem' : 'fcdistro',
-            #'site' : 'pldistro',
             'minReliability' : 'reliability%s' % timeframe,
             'maxReliability' : 'reliability%s' % timeframe,
             'minBandwidth' : 'bw%s' % timeframe,
@@ -401,7 +422,7 @@ class PlanetlabNode(LinuxNode):
         for attr_name, attr_obj in self._attrs.iteritems():
             attr_value = self.get(attr_name)
             
-            if attr_value is not None and attr_obj.flags == 8 and \
+            if attr_value is not None and attr_obj.has_flag(Flags.Filter) and \
                 attr_name != 'timeframe':
         
                 attr_tag = attr_to_tags[attr_name]
@@ -527,7 +548,7 @@ class PlanetlabNode(LinuxNode):
                     ping_ok = self._do_ping(node_id)
                     if not ping_ok:
                         self._set_hostname_attr(node_id)
-                        self.warn(" Node not responding PING ")
+                        self.warning(" Node not responding PING ")
                         self._blacklist_node(node_id)
                     else:
                         # discovered node for provision, added to provision list
@@ -542,20 +563,21 @@ class PlanetlabNode(LinuxNode):
         slicename = self.get("username")
         with PlanetlabNode.lock:
             slice_nodes = self.plapi.get_slice_nodes(slicename)
+            self.debug(" Previous slice nodes %s " % slice_nodes)
             slice_nodes.append(node_id)
             self.plapi.add_slice_nodes(slicename, slice_nodes)
 
     def _delete_node_from_slice(self, node):
-        self.warn(" Deleting node from slice ")
+        self.warning(" Deleting node from slice ")
         slicename = self.get("username")
         self.plapi.delete_slice_node(slicename, [node])
 
     def _get_hostname(self):
         hostname = self.get("hostname")
-        ip = self.get("ip")
         if hostname:
             return hostname
-        elif ip:
+        ip = self.get("ip")
+        if ip:
             hostname = socket.gethostbyaddr(ip)[0]
             self.set('hostname', hostname)
             return hostname
@@ -586,23 +608,21 @@ class PlanetlabNode(LinuxNode):
         """
         ping_ok = False
         ip = self._get_ip(node_id)
-        if not ip: return ping_ok
-
-        command = ['ping', '-c4']
-        command.append(ip)
-
-        (out, err) = lexec(command)
-        if not out.find("2 received") or not out.find("3 received") or not \
-            out.find("4 received") < 0:
-            ping_ok = True
-        
+        if ip:
+            command = "ping -c4 %s" % ip
+            (out, err) = lexec(command)
+
+            m = re.search("(\d+)% packet loss", str(out))
+            if m and int(m.groups()[0]) < 50:
+                ping_ok = True
+       
         return ping_ok 
 
     def _blacklist_node(self, node):
         """
         Add node mal functioning node to blacklist
         """
-        self.warn(" Blacklisting malfunctioning node ")
+        self.warning(" Blacklisting malfunctioning node ")
         self.plapi.blacklist_host(node)
         if not self._hostname:
             self.set('hostname', None)
@@ -618,9 +638,10 @@ class PlanetlabNode(LinuxNode):
         """
         Query PLCAPI for the IP of a node with certain node id
         """
-        hostname = self.plapi.get_nodes(node_id, ['hostname'])[0]
+        hostname = self.get("hostname") or \
+            self.plapi.get_nodes(node_id, ['hostname'])[0]['hostname']
         try:
-            ip = sshfuncs.gethostbyname(hostname['hostname'])
+            ip = sshfuncs.gethostbyname(hostname)
         except:
             # Fail while trying to find the IP
             return None
index a2111f4..39567b3 100644 (file)
@@ -52,13 +52,13 @@ class OVSSwitch(LinuxApplication):
 
         """
         bridge_name = Attribute("bridge_name", "Name of the switch/bridge",
-                flags = Flags.ExecReadOnly)    
+                flags = Flags.Design)  
         virtual_ip_pref = Attribute("virtual_ip_pref", "Virtual IP/PREFIX of the switch",
-                flags = Flags.ExecReadOnly)       
+                flags = Flags.Design)  
         controller_ip = Attribute("controller_ip", "IP of the controller",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)  
         controller_port = Attribute("controller_port", "Port of the controller",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)  
 
         cls._register_attribute(bridge_name)
         cls._register_attribute(virtual_ip_pref)
index 554a116..481fe05 100644 (file)
@@ -51,7 +51,7 @@ class OVSPort(LinuxApplication):
 
         """
         port_name = Attribute("port_name", "Name of the port",
-            flags = Flags.ExecReadOnly)                        
+            flags = Flags.Design)                      
 
         cls._register_attribute(port_name)
 
index 23b0846..a26f441 100644 (file)
@@ -58,7 +58,7 @@ class OVSTunnel(LinuxApplication):
 
         """
         network = Attribute("network", "IPv4 Network Address",
-               flags = Flags.ExecReadOnly)
+               flags = Flags.Design)
 
         cipher = Attribute("cipher",
                "Cipher to encript communication. "
@@ -66,25 +66,25 @@ class OVSTunnel(LinuxApplication):
                 default = None,
                 allowed = ["PLAIN", "AES", "Blowfish", "DES", "DES3"],
                 type = Types.Enumerate, 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         cipher_key = Attribute("cipherKey",
                 "Specify a symmetric encryption key with which to protect "
                 "packets across the tunnel. python-crypto must be installed "
                 "on the system." ,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         txqueuelen = Attribute("txQueueLen",
                 "Specifies the interface's transmission queue length. "
                 "Defaults to 1000. ", 
                 type = Types.Integer, 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         bwlimit = Attribute("bwLimit",
                 "Specifies the interface's emulated bandwidth in bytes "
                 "per second.",
                 type = Types.Integer, 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         cls._register_attribute(network)
         cls._register_attribute(cipher)
index 742c3f0..4f4bf5c 100644 (file)
@@ -20,6 +20,7 @@
 import functools
 import hashlib
 import socket
+import os
 import time
 import threading
 import xmlrpclib
@@ -135,16 +136,15 @@ class PLCAPI(object):
      
     _required_methods = set()
 
-    def __init__(self, username = None, password = None, session_key = None, 
-            proxy = None,
-            hostname = "www.planet-lab.eu",
-            urlpattern = "https://%(hostname)s:443/PLCAPI/",
+    def __init__(self, username, password, hostname, urlpattern, ec, proxy, session_key = None, 
             local_peer = "PLE"):
 
         self._blacklist = set()
         self._reserved = set()
         self._nodes_cache = None
         self._already_cached = False
+        self._ecobj = ec
+        self.count = 1 
 
         if session_key is not None:
             self.auth = dict(AuthMethod='session', session=session_key)
@@ -175,7 +175,11 @@ class PLCAPI(object):
             self._proxy_transport = lambda : None
         
         self.threadlocal = threading.local()
-    
+
+        # Load blacklist from file
+        if self._ecobj.get_global('PlanetlabNode', 'persist_blacklist'):
+            self._set_blacklist()
+
     @property
     def api(self):
         # Cannot reuse same proxy in all threads, py2.7 is not threadsafe
@@ -192,6 +196,7 @@ class PLCAPI(object):
             return self.api
         
     def test(self):
+        # TODO: Use nepi utils Logger instead of warning!!
         import warnings
         
         # validate XMLRPC server checking supported API calls
@@ -212,6 +217,16 @@ class PLCAPI(object):
             warnings.warn(str(e))
         
         return True
+
+    def _set_blacklist(self):
+        nepi_home = os.path.join(os.path.expanduser("~"), ".nepi")
+        plblacklist_file = os.path.join(nepi_home, "plblacklist.txt")
+        with open(plblacklist_file, 'r') as f:
+            hosts_tobl = f.read().splitlines()
+            if hosts_tobl:
+                nodes_id = self.get_nodes(hosts_tobl, ['node_id'])
+                for node_id in nodes_id:
+                    self._blacklist.add(node_id['node_id'])
     
     @property
     def network_types(self):
@@ -428,8 +443,8 @@ class PLCAPI(object):
     def get_slice_nodes(self, slicename):
         return self.get_slices(slicename, ['node_ids'])[0]['node_ids']
 
-    def add_slice_nodes(self, slicename, nodes = None):
-        self.update_slice(slicename, nodes = nodes)
+    def add_slice_nodes(self, slicename, nodes):
+        self.update_slice(slicename, nodes=nodes)
 
     def get_node_info(self, node_id):
         self.start_multicall()
@@ -458,24 +473,39 @@ class PLCAPI(object):
         else:
             return None
 
-    def blacklist_host(self, hostname):
-        self._blacklist.add(hostname)
+    def blacklist_host(self, node_id):
+        self._blacklist.add(node_id)
 
     def blacklisted(self):
-        return self._blacklist
+        return self._blacklist 
 
-    def unblacklist_host(self, hostname):
-        del self._blacklist[hostname]
+    def unblacklist_host(self, node_id):
+        del self._blacklist[node_id]
 
-    def reserve_host(self, hostname):
-        self._reserved.add(hostname)
+    def reserve_host(self, node_id):
+        self._reserved.add(node_id)
 
     def reserved(self):
         return self._reserved
 
-    def unreserve_host(self, hostname):
-        del self._reserved[hostname]
+    def unreserve_host(self, node_id):
+        del self._reserved[node_id]
 
+    def release(self):
+        self.count -= 1
+        if self._ecobj.get_global('PlanetlabNode', 'persist_blacklist') and self.count == 0:
+            if self._blacklist:
+                to_blacklist = list()
+                hostnames = self.get_nodes(list(self._blacklist), ['hostname'])
+                for hostname in hostnames:
+                    to_blacklist.append(hostname['hostname'])
+
+                nepi_home = os.path.join(os.path.expanduser("~"), ".nepi")
+                plblacklist_file = os.path.join(nepi_home, "plblacklist.txt")
+
+                with open(plblacklist_file, 'w') as f:
+                    for host in to_blacklist:
+                        f.write("%s\n" % host)
 
 class PLCAPIFactory(object):
     """ 
@@ -491,8 +521,7 @@ class PLCAPIFactory(object):
 
     @classmethod 
     def get_api(cls, pl_user, pl_pass, pl_host,
-            pl_ptn = "https://%(hostname)s:443/PLCAPI/",
-            proxy = None):
+            pl_ptn, ec, proxy = None):
         """ Get existing PLCAPI instance
 
         :param pl_user: Planelab user name (used for web login)
@@ -511,14 +540,15 @@ class PLCAPIFactory(object):
             with cls._lock:
                 api = cls._apis.get(key)
                 if not api:
-                    api = cls.create_api(pl_user, pl_pass, pl_host, pl_ptn, proxy)
+                    api = cls.create_api(pl_user, pl_pass, pl_host, pl_ptn, ec, proxy)
+                else:
+                    api.count += 1
                 return api
         return None
 
     @classmethod 
     def create_api(cls, pl_user, pl_pass, pl_host,
-            pl_ptn = "https://%(hostname)s:443/PLCAPI/",
-            proxy = None):
+            pl_ptn, ec, proxy = None):
         """ Create an PLCAPI instance
 
         :param pl_user: Planelab user name (used for web login)
@@ -532,13 +562,8 @@ class PLCAPIFactory(object):
         :param proxy: Proxy service url
         :type pl_ptn: str
         """
-        api = PLCAPI(
-            username = pl_user,
-            password = pl_pass,
-            hostname = pl_host,
-            urlpattern = pl_ptn,
-            proxy = proxy
-        )
+        api = PLCAPI(username = pl_user, password = pl_pass, hostname = pl_host,
+            urlpattern = pl_ptn, ec = ec, proxy = proxy)
         key = cls._make_key(pl_user, pl_host)
         cls._apis[key] = api
         return api
@@ -554,3 +579,4 @@ class PLCAPIFactory(object):
         skey = "".join(map(str, args))
         return hashlib.md5(skey).hexdigest()
 
+
diff --git a/src/nepi/resources/planetlab/sfa_node.py b/src/nepi/resources/planetlab/sfa_node.py
new file mode 100644 (file)
index 0000000..9a0684b
--- /dev/null
@@ -0,0 +1,635 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState, reschedule_delay 
+from nepi.resources.linux.node import LinuxNode
+from nepi.util.sfaapi import SFAAPIFactory 
+from nepi.util.execfuncs import lexec
+from nepi.util import sshfuncs
+
+from random import randint
+import re
+import weakref
+import time
+import socket
+import threading
+import datetime
+
+@clsinit_copy
+class PlanetlabSfaNode(LinuxNode):
+    _rtype = "PlanetlabSfaNode"
+    _help = "Controls a PlanetLab host accessible using a SSH key " \
+            "and provisioned using SFA"
+    _backend = "planetlab"
+
+    @classmethod
+    def _register_attributes(cls):
+
+        sfa_user = Attribute("sfauser", "SFA user",
+                    flags = Flags.Credential)
+
+        sfa_private_key = Attribute("sfaPrivateKey", "SFA path to the private key \
+                            used to generate the user credential")
+
+        city = Attribute("city", "Constrain location (city) during resource \
+                discovery. May use wildcards.",
+                flags = Flags.Filter)
+
+        country = Attribute("country", "Constrain location (country) during \
+                    resource discovery. May use wildcards.",
+                    flags = Flags.Filter)
+
+        region = Attribute("region", "Constrain location (region) during \
+                    resource discovery. May use wildcards.",
+                    flags = Flags.Filter)
+
+        architecture = Attribute("architecture", "Constrain architecture \
+                        during resource discovery.",
+                        type = Types.Enumerate,
+                        allowed = ["x86_64", 
+                                    "i386"],
+                        flags = Flags.Filter)
+
+        operating_system = Attribute("operatingSystem", "Constrain operating \
+                            system during resource discovery.",
+                            type = Types.Enumerate,
+                            allowed =  ["f8",
+                                        "f12",
+                                        "f14",
+                                        "centos",
+                                        "other"],
+                            flags = Flags.Filter)
+
+        min_reliability = Attribute("minReliability", "Constrain reliability \
+                            while picking PlanetLab nodes. Specifies a lower \
+                            acceptable bound.",
+                            type = Types.Double,
+                            range = (1, 100),
+                            flags = Flags.Filter)
+
+        max_reliability = Attribute("maxReliability", "Constrain reliability \
+                            while picking PlanetLab nodes. Specifies an upper \
+                            acceptable bound.",
+                            type = Types.Double,
+                            range = (1, 100),
+                            flags = Flags.Filter)
+
+        min_bandwidth = Attribute("minBandwidth", "Constrain available \
+                            bandwidth while picking PlanetLab nodes. \
+                            Specifies a lower acceptable bound.",
+                            type = Types.Double,
+                            range = (0, 2**31),
+                            flags = Flags.Filter)
+
+        max_bandwidth = Attribute("maxBandwidth", "Constrain available \
+                            bandwidth while picking PlanetLab nodes. \
+                            Specifies an upper acceptable bound.",
+                            type = Types.Double,
+                            range = (0, 2**31),
+                            flags = Flags.Filter)
+
+        min_load = Attribute("minLoad", "Constrain node load average while \
+                    picking PlanetLab nodes. Specifies a lower acceptable \
+                    bound.",
+                    type = Types.Double,
+                    range = (0, 2**31),
+                    flags = Flags.Filter)
+
+        max_load = Attribute("maxLoad", "Constrain node load average while \
+                    picking PlanetLab nodes. Specifies an upper acceptable \
+                    bound.",
+                    type = Types.Double,
+                    range = (0, 2**31),
+                    flags = Flags.Filter)
+
+        min_cpu = Attribute("minCpu", "Constrain available cpu time while \
+                    picking PlanetLab nodes. Specifies a lower acceptable \
+                    bound.",
+                    type = Types.Double,
+                    range = (0, 100),
+                    flags = Flags.Filter)
+
+        max_cpu = Attribute("maxCpu", "Constrain available cpu time while \
+                    picking PlanetLab nodes. Specifies an upper acceptable \
+                    bound.",
+                    type = Types.Double,
+                    range = (0, 100),
+                    flags = Flags.Filter)
+
+        timeframe = Attribute("timeframe", "Past time period in which to check\
+                        information about the node. Values are year,month, \
+                        week, latest",
+                        default = "week",
+                        type = Types.Enumerate,
+                        allowed = ["latest",
+                                    "week",
+                                    "month",
+                                    "year"],
+                        flags = Flags.Filter)
+
+        plblacklist = Attribute("persist_blacklist", "Take into account the file plblacklist \
+                        in the user's home directory under .nepi directory. This file \
+                        contains a list of PL nodes to blacklist, and at the end \
+                        of the experiment execution the new blacklisted nodes are added.",
+                    type = Types.Bool,
+                    default = False,
+                    flags = Flags.Global)
+
+        cls._register_attribute(sfa_user)
+        cls._register_attribute(sfa_private_key)
+        cls._register_attribute(city)
+        cls._register_attribute(country)
+        cls._register_attribute(region)
+        cls._register_attribute(architecture)
+        cls._register_attribute(operating_system)
+        cls._register_attribute(min_reliability)
+        cls._register_attribute(max_reliability)
+        cls._register_attribute(min_bandwidth)
+        cls._register_attribute(max_bandwidth)
+        cls._register_attribute(min_load)
+        cls._register_attribute(max_load)
+        cls._register_attribute(min_cpu)
+        cls._register_attribute(max_cpu)
+        cls._register_attribute(timeframe)
+        cls._register_attribute(plblacklist)
+
+    def __init__(self, ec, guid):
+        super(PlanetlabSfaNode, self).__init__(ec, guid)
+        
+        self._ecobj = weakref.ref(ec)
+        self._sfaapi = None
+        self._node_to_provision = None
+        self._slicenode = False
+        self._hostname = False
+
+        if self.get("gateway") or self.get("gatewayUser"):
+            self.set("gateway", None)
+            self.set("gatewayUser", None)
+
+    def _skip_provision(self):
+        sfa_user = self.get("sfauser")
+        if not sfa_user:
+            return True
+        else: return False
+    
+    @property
+    def sfaapi(self):
+        if not self._sfaapi:
+            sfa_user = self.get("sfauser")
+            sfa_sm = "http://sfa3.planet-lab.eu:12346/"
+            sfa_auth = '.'.join(sfa_user.split('.')[:2])
+            sfa_registry = "http://sfa3.planet-lab.eu:12345/"
+            sfa_private_key = self.get("sfaPrivateKey")
+
+            _sfaapi = SFAAPIFactory.get_api(sfa_user, sfa_auth, 
+                sfa_registry, sfa_sm, sfa_private_key, self._ecobj())
+
+            if not _sfaapi:
+                self.fail_sfaapi()
+    
+            self._sfaapi = weakref.ref(_sfaapi)
+
+        return self._sfaapi()
+
+    def do_discover(self):
+        """
+        Based on the attributes defined by the user, discover the suitable 
+        nodes for provision.
+        """
+        if self._skip_provision():
+            super(PlanetlabSfaNode, self).do_discover()
+            return
+
+        nodes = self.sfaapi.get_resources_hrn()
+
+        hostname = self._get_hostname()
+        if hostname:
+            # the user specified one particular node to be provisioned
+            self._hostname = True
+            host_hrn = nodes[hostname]
+
+            # check that the node is not blacklisted or being provisioned
+            # by other RM
+            if not self._blacklisted(host_hrn):
+                if not self._reserved(host_hrn):
+                    # Node in reservation
+                    ping_ok = self._do_ping(hostname)
+                    if not ping_ok:
+                        self._blacklist_node(host_hrn)
+                        self.fail_node_not_alive(hostname)
+                    else:
+                        if self._check_if_in_slice([host_hrn]):
+                            self._slicenode = True
+                        self._node_to_provision = host_hrn
+                        super(PlanetlabSfaNode, self).do_discover()
+        
+#        else:
+#            # the user specifies constraints based on attributes, zero, one or 
+#            # more nodes can match these constraints 
+#            nodes = self._filter_based_on_attributes()
+#
+#            # nodes that are already part of user's slice have the priority to
+#            # provisioned
+#            nodes_inslice = self._check_if_in_slice(nodes)
+#            nodes_not_inslice = list(set(nodes) - set(nodes_inslice))
+#            
+#            node_id = None
+#            if nodes_inslice:
+#                node_id = self._choose_random_node(nodes_inslice)
+#                self._slicenode = True                
+#                
+#            if not node_id:
+#                # Either there were no matching nodes in the user's slice, or
+#                # the nodes in the slice  were blacklisted or being provisioned
+#                # by other RM. Note nodes_not_inslice is never empty
+#                node_id = self._choose_random_node(nodes_not_inslice)
+#                self._slicenode = False
+#
+#            if node_id:
+#                self._node_to_provision = node_id
+#                try:
+#                    self._set_hostname_attr(node_id)
+#                    self.info(" Selected node to provision ")
+#                    super(PlanetlabSfaNode, self).do_discover()
+#                except:
+#                    with PlanetlabSfaNode.lock:
+#                        self._blacklist_node(node_id)
+#                    self.do_discover()
+#            else:
+#               self.fail_not_enough_nodes() 
+#    
+    def _blacklisted(self, host_hrn):
+        if self.sfaapi.blacklisted(host_hrn):
+           self.fail_node_not_available(hostname)
+        return False
+
+    def _reserved(self, host_hrn):
+        if self.sfaapi.reserved(host_hrn):
+            self.fail_node_not_available(hostname)
+        return False
+            
+    def do_provision(self):
+        """
+        Add node to user's slice after verifing that the node is functioning
+        correctly.
+        """
+        if self._skip_provision():
+            super(PlanetlabSfaNode, self).do_provision()
+            return
+
+        provision_ok = False
+        ssh_ok = False
+        proc_ok = False
+        timeout = 1800
+
+        while not provision_ok:
+            node = self._node_to_provision
+            if not self._slicenode:
+                self._add_node_to_slice(node)
+            
+                # check ssh connection
+                t = 0 
+                while t < timeout and not ssh_ok:
+
+                    cmd = 'echo \'GOOD NODE\''
+                    ((out, err), proc) = self.execute(cmd)
+                    if out.find("GOOD NODE") < 0:
+                        self.debug( "No SSH connection, waiting 60s" )
+                        t = t + 60
+                        time.sleep(60)
+                        continue
+                    else:
+                        self.debug( "SSH OK" )
+                        ssh_ok = True
+                        continue
+            else:
+                cmd = 'echo \'GOOD NODE\''
+                ((out, err), proc) = self.execute(cmd)
+                if not out.find("GOOD NODE") < 0:
+                    ssh_ok = True
+
+            if not ssh_ok:
+                # the timeout was reach without establishing ssh connection
+                # the node is blacklisted, deleted from the slice, and a new
+                # node to provision is discovered
+                self.warn(" Could not SSH login ")
+                self._blacklist_node(node)
+                self.do_discover()
+                continue
+            
+            # check /proc directory is mounted (ssh_ok = True)
+            # and file system is not read only
+            else:
+                cmd = 'mount |grep proc'
+                ((out1, err1), proc1) = self.execute(cmd)
+                cmd = 'touch /tmp/tmpfile; rm /tmp/tmpfile'
+                ((out2, err2), proc2) = self.execute(cmd)
+                if out1.find("/proc type proc") < 0 or \
+                    "Read-only file system".lower() in err2.lower():
+                    self.warn(" Corrupted file system ")
+                    self._blacklist_node(node)
+                    self.do_discover()
+                    continue
+            
+                else:
+                    provision_ok = True
+                    if not self.get('hostname'):
+                        self._set_hostname_attr(node)            
+                    self.info(" Node provisioned ")            
+            
+        super(PlanetlabSfaNode, self).do_provision()
+
+#    def _filter_based_on_attributes(self):
+#        """
+#        Retrive the list of nodes hrn that match user's constraints 
+#        """
+#        # Map user's defined attributes with tagnames of PlanetLab
+#        timeframe = self.get("timeframe")[0]
+#        attr_to_tags = {
+#            'city' : 'city',
+#            'country' : 'country',
+#            'region' : 'region',
+#            'architecture' : 'arch',
+#            'operatingSystem' : 'fcdistro',
+#            'minReliability' : 'reliability%s' % timeframe,
+#            'maxReliability' : 'reliability%s' % timeframe,
+#            'minBandwidth' : 'bw%s' % timeframe,
+#            'maxBandwidth' : 'bw%s' % timeframe,
+#            'minLoad' : 'load%s' % timeframe,
+#            'maxLoad' : 'load%s' % timeframe,
+#            'minCpu' : 'cpu%s' % timeframe,
+#            'maxCpu' : 'cpu%s' % timeframe,
+#        }
+#        
+#        nodes_hrn = []
+#        filters = {}
+#
+#        for attr_name, attr_obj in self._attrs.iteritems():
+#            attr_value = self.get(attr_name)
+#            
+#            if attr_value is not None and attr_obj.has_flag(Flags.Filter) and \
+#                attr_name != 'timeframe':
+#        
+#                attr_tag = attr_to_tags[attr_name]
+#                filters['tagname'] = attr_tag
+#
+#                # filter nodes by fixed constraints e.g. operating system
+#                if not 'min' in attr_name and not 'max' in attr_name:
+#                    filters['value'] = attr_value
+#                    nodes_hrn = self._filter_by_fixed_attr(filters, nodes_hrn)
+#
+#                # filter nodes by range constraints e.g. max bandwidth
+#                elif ('min' or 'max') in attr_name:
+#                    nodes_hrn = self._filter_by_range_attr(attr_name, attr_value, filters, nodes_hrn)
+#
+#        if not filters:
+#            nodes = self.sfaapi.get_resources_hrn()
+#            for node in nodes:
+#                nodes_hrn.append(node[node.key()])
+#        return nodes_hrn
+#                    
+#    def _filter_by_fixed_attr(self, filters, nodes_hrn):
+#        """
+#        Query SFA API for nodes matching fixed attributes defined by the
+#        user
+#        """
+#        pass
+##        node_tags = self.sfaapi.get_resources_tags(filters)
+##        if node_tags is not None:
+##
+##            if len(nodes_id) == 0:
+##                # first attribute being matched
+##                for node_tag in node_tags:
+##                    nodes_id.append(node_tag['node_id'])
+##            else:
+##                # remove the nodes ids that don't match the new attribute
+##                # that is being match
+##
+##                nodes_id_tmp = []
+##                for node_tag in node_tags:
+##                    if node_tag['node_id'] in nodes_id:
+##                        nodes_id_tmp.append(node_tag['node_id'])
+##
+##                if len(nodes_id_tmp):
+##                    nodes_id = set(nodes_id) & set(nodes_id_tmp)
+##                else:
+##                    # no node from before match the new constraint
+##                    self.fail_discovery()
+##        else:
+##            # no nodes match the filter applied
+##            self.fail_discovery()
+##
+##        return nodes_id
+#
+#    def _filter_by_range_attr(self, attr_name, attr_value, filters, nodes_id):
+#        """
+#        Query PLCAPI for nodes ids matching attributes defined in a certain
+#        range, by the user
+#        """
+#        pass
+##        node_tags = self.plapi.get_node_tags(filters)
+##        if node_tags:
+##            
+##            if len(nodes_id) == 0:
+##                # first attribute being matched
+##                for node_tag in node_tags:
+## 
+##                   # check that matches the min or max restriction
+##                    if 'min' in attr_name and node_tag['value'] != 'n/a' and \
+##                        float(node_tag['value']) > attr_value:
+##                        nodes_id.append(node_tag['node_id'])
+##
+##                    elif 'max' in attr_name and node_tag['value'] != 'n/a' and \
+##                        float(node_tag['value']) < attr_value:
+##                        nodes_id.append(node_tag['node_id'])
+##            else:
+##
+##                # remove the nodes ids that don't match the new attribute
+##                # that is being match
+##                nodes_id_tmp = []
+##                for node_tag in node_tags:
+##
+##                    # check that matches the min or max restriction and was a
+##                    # matching previous filters
+##                    if 'min' in attr_name and node_tag['value'] != 'n/a' and \
+##                        float(node_tag['value']) > attr_value and \
+##                        node_tag['node_id'] in nodes_id:
+##                        nodes_id_tmp.append(node_tag['node_id'])
+##
+##                    elif 'max' in attr_name and node_tag['value'] != 'n/a' and \
+##                        float(node_tag['value']) < attr_value and \
+##                        node_tag['node_id'] in nodes_id:
+##                        nodes_id_tmp.append(node_tag['node_id'])
+##
+##                if len(nodes_id_tmp):
+##                    nodes_id = set(nodes_id) & set(nodes_id_tmp)
+##                else:
+##                    # no node from before match the new constraint
+##                    self.fail_discovery()
+##
+##        else: #TODO CHECK
+##            # no nodes match the filter applied
+##            self.fail_discovery()
+##
+##        return nodes_id
+#        
+#    def _choose_random_node(self, nodes):
+#        """
+#        From the possible nodes for provision, choose randomly to decrese the
+#        probability of different RMs choosing the same node for provision
+#        """
+#        size = len(nodes)
+#        while size:
+#            size = size - 1
+#            index = randint(0, size)
+#            node_id = nodes[index]
+#            nodes[index] = nodes[size]
+#
+#            # check the node is not blacklisted or being provision by other RM
+#            # and perform ping to check that is really alive
+#            with PlanetlabNode.lock:
+#
+#                blist = self.plapi.blacklisted()
+#                plist = self.plapi.reserved()
+#                if node_id not in blist and node_id not in plist:
+#                    ping_ok = self._do_ping(node_id)
+#                    if not ping_ok:
+#                        self._set_hostname_attr(node_id)
+#                        self.warn(" Node not responding PING ")
+#                        self._blacklist_node(node_id)
+#                    else:
+#                        # discovered node for provision, added to provision list
+#                        self._put_node_in_provision(node_id)
+#                        return node_id
+#
+#    def _get_nodes_id(self, filters=None):
+#        return self.plapi.get_nodes(filters, fields=['node_id'])
+#
+    def _add_node_to_slice(self, host_hrn):
+        self.info(" Adding node to slice ")
+        slicename = self.get("username").replace('_', '.')
+        slicename = 'ple.' + slicename
+        self.sfaapi.add_resource_to_slice(slicename, host_hrn)
+
+#    def _delete_node_from_slice(self, node):
+#        self.warn(" Deleting node from slice ")
+#        slicename = self.get("username")
+#        self.plapi.delete_slice_node(slicename, [node])
+#
+    def _get_hostname(self):
+        hostname = self.get("hostname")
+        if hostname:
+            return hostname
+        else:
+            return None
+
+    def _set_hostname_attr(self, node):
+        """
+        Query SFAAPI for the hostname of a certain host hrn and sets the
+        attribute hostname, it will over write the previous value
+        """
+        hosts_hrn = self.sfaapi.get_resources_hrn()
+        for hostname, hrn  in hosts_hrn.iteritems():
+            if hrn == node:
+                self.set("hostname", hostname)
+
+    def _check_if_in_slice(self, hosts_hrn):
+        """
+        Check using SFA API if any host hrn from hosts_hrn is in the user's
+        slice
+        """
+        slicename = self.get("username").replace('_', '.')
+        slicename = 'ple.' + slicename
+        slice_nodes = self.sfaapi.get_slice_resources(slicename)['resource']
+        slice_nodes_hrn = self.sfaapi.get_resources_hrn(slice_nodes)
+        nodes_inslice = list(set(hosts_hrn) & set(slice_nodes_hrn.values()))
+        return nodes_inslice
+
+    def _do_ping(self, hostname):
+        """
+        Perform ping command on node's IP matching hostname
+        """
+        ping_ok = False
+        ip = self._get_ip(hostname)
+        if ip:
+            command = "ping -c4 %s" % ip
+            (out, err) = lexec(command)
+
+            m = re.search("(\d+)% packet loss", str(out))
+            if m and int(m.groups()[0]) < 50:
+                ping_ok = True
+
+        return ping_ok
+
+    def _blacklist_node(self, host_hrn):
+        """
+        Add node mal functioning node to blacklist
+        """
+        self.warning(" Blacklisting malfunctioning node ")
+        self.sfaapi.blacklist_resource(host_hrn)
+        if not self._hostname:
+            self.set('hostname', None)
+
+    def _reserve(self, host_hrn):
+        """
+        Add node to the list of nodes being provisioned, in order for other RMs
+        to not try to provision the same one again.
+        """
+        self.sfaapi.reserve_resource(host_hrn)
+
+    def _get_ip(self, hostname):
+        """
+        Query cache for the IP of a node with certain hostname
+        """
+        try:
+            ip = sshfuncs.gethostbyname(hostname)
+        except:
+            # Fail while trying to find the IP
+            return None
+        return ip
+
+    def fail_discovery(self):
+        msg = "Discovery failed. No candidates found for node"
+        self.error(msg)
+        raise RuntimeError, msg
+
+    def fail_node_not_alive(self, hostname=None):
+        msg = "Node %s not alive" % hostname
+        raise RuntimeError, msg
+    
+    def fail_node_not_available(self, hostname):
+        msg = "Node %s not available for provisioning" % hostname
+        raise RuntimeError, msg
+
+    def fail_not_enough_nodes(self):
+        msg = "Not enough nodes available for provisioning"
+        raise RuntimeError, msg
+
+    def fail_sfaapi(self):
+        msg = "Failing while trying to instanciate the SFA API.\nSet the" + \
+            " attributes sfauser and sfaPrivateKey."
+        raise RuntimeError, msg
+
+    def valid_connection(self, guid):
+        # TODO: Validate!
+        return True
+
+
index dc42a30..6d1be50 100644 (file)
@@ -42,35 +42,35 @@ class PlanetlabTap(LinuxApplication):
     @classmethod
     def _register_attributes(cls):
         ip4 = Attribute("ip4", "IPv4 Address",
-              flags = Flags.ExecReadOnly)
+              flags = Flags.Design)
 
         mac = Attribute("mac", "MAC Address",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         prefix4 = Attribute("prefix4", "IPv4 network prefix",
                 type = Types.Integer,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         mtu = Attribute("mtu", "Maximum transmition unit for device",
                 type = Types.Integer)
 
         devname = Attribute("deviceName", 
                 "Name of the network interface (e.g. eth0, wlan0, etc)",
-                flags = Flags.ReadOnly)
+                flags = Flags.NoWrite)
 
         up = Attribute("up", "Link up", 
                 type = Types.Bool)
         
         snat = Attribute("snat", "Set SNAT=1", 
                 type = Types.Bool,
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
         
         pointopoint = Attribute("pointopoint", "Peer IP address", 
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         tear_down = Attribute("tearDown", "Bash script to be executed before " + \
                 "releasing the resource",
-                flags = Flags.ExecReadOnly)
+                flags = Flags.Design)
 
         cls._register_attribute(ip4)
         cls._register_attribute(mac)
@@ -169,7 +169,6 @@ class PlanetlabTap(LinuxApplication):
             self.do_discover()
             self.do_provision()
 
-            self.debug("----- READY ---- ")
             self.set_ready()
 
     def do_start(self):
index 681e755..7007561 100644 (file)
@@ -40,10 +40,10 @@ class PlanetlabVroute(LinuxApplication):
     def _register_attributes(cls):
         action = Attribute("action", "Either add or del",
               allowed = ["add", "del"],
-              flags = Flags.ExecReadOnly)
+              flags = Flags.Design)
 
         network = Attribute("network", "IPv4 Network Address",
-              flags = Flags.ExecReadOnly)
+              flags = Flags.Design)
 
         cls._register_attribute(action)
         cls._register_attribute(network)
index eaadf50..6b5f1a5 100644 (file)
 #
 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
 
-from nepi.util.sshfuncs import ProcStatus, STDOUT
+from nepi.util.sshfuncs import ProcStatus, STDOUT, log, shell_escape
 
+import logging
+import shlex
 import subprocess
 
 def lexec(command, 
         user = None, 
         sudo = False,
-        stdin = None,
         env = None):
     """
     Executes a local command, returns ((stdout,stderr),process)
@@ -37,38 +38,62 @@ def lexec(command,
 
     if sudo:
         command = "sudo %s" % command
-    elif user:
-        command = "su %s ; %s " % (user, command)
+    
+    # XXX: Doing 'su user' blocks waiting for a password on stdin
+    #elif user:
+    #    command = "su %s ; %s " % (user, command)
+
+    proc = subprocess.Popen(command,
+                shell = True, 
+                stdout = subprocess.PIPE, 
+                stderr = subprocess.PIPE)
 
+    out = err = ""
+    log_msg = "lexec - command %s " % command
 
-    p = subprocess.Popen(command, 
-            stdout = subprocess.PIPE, 
-            stderr = subprocess.PIPE,
-            stdin  = stdin)
+    try:
+        out, err = proc.communicate()
+        log(log_msg, logging.DEBUG, out, err)
+    except:
+        log(log_msg, logging.ERROR, out, err)
+        raise
 
-    out, err = p.communicate()
-    return (out, err)
+    return ((out, err), proc)
 
 def lcopy(source, dest, recursive = False):
     """
     Copies from/to localy.
     """
     
-    if TRACE:
-        print "scp", source, dest
-    
-    command = ["cp"]
+    args = ["cp"]
     if recursive:
-        command.append("-R")
-    
-    command.append(src)
-    command.append(dst)
-    
-    p = subprocess.Popen(command, 
+        args.append("-r")
+  
+    if isinstance(source, list):
+        args.extend(source)
+    else:
+        args.append(source)
+
+    if isinstance(dest, list):
+        args.extend(dest)
+    else:
+        args.append(dest)
+
+    proc = subprocess.Popen(args, 
         stdout=subprocess.PIPE, 
         stderr=subprocess.PIPE)
 
-    out, err = p.communicate()
+    out = err = ""
+    command = " ".join(args)
+    log_msg = " lcopy - command %s " % command
+
+    try:
+        out, err = proc.communicate()
+        log(log_msg, logging.DEBUG, out, err)
+    except:
+        log(log_msg, logging.ERROR, out, err)
+        raise
+
     return ((out, err), proc)
    
 def lspawn(command, pidfile, 
@@ -120,7 +145,7 @@ def lspawn(command, pidfile,
         'stdin' : stdin,
     }
     
-    cmd = "%(create)s%(gohome)s rm -f %(pidfile)s ; %(sudo)s nohup bash -c %(command)s " % {
+    cmd = "%(create)s%(gohome)s rm -f %(pidfile)s ; %(sudo)s bash -c %(command)s " % {
             'command' : shell_escape(daemon_command),
             'sudo' : 'sudo -S' if sudo else '',
             'pidfile' : shell_escape(pidfile),
@@ -128,12 +153,12 @@ def lspawn(command, pidfile,
             'create' : 'mkdir -p %s ; ' % (shell_escape(home),) if create_home else '',
         }
 
-    (out,err),proc = lexec(cmd)
+    (out,err), proc = lexec(cmd)
     
     if proc.wait():
         raise RuntimeError, "Failed to set up application on host %s: %s %s" % (host, out,err,)
 
-    return (out,err),proc
+    return ((out,err), proc)
 
 def lgetpid(pidfile):
     """
@@ -148,7 +173,7 @@ def lgetpid(pidfile):
         or None if the pidfile isn't valid yet (maybe the process is still starting).
     """
 
-    (out,err),proc = lexec("cat %s" % pidfile )
+    (out,err), proc = lexec("cat %s" % pidfile )
         
     if proc.wait():
         return None
@@ -172,7 +197,7 @@ def lstatus(pid, ppid):
         One of NOT_STARTED, RUNNING, FINISHED
     """
 
-    (out,err),proc = lexec(
+    (out,err), proc = lexec(
         # Check only by pid. pid+ppid does not always work (especially with sudo) 
         " (( ps --pid %(pid)d -o pid | grep -c %(pid)d && echo 'wait')  || echo 'done' ) | tail -n 1" % {
             'ppid' : ppid,
@@ -187,8 +212,8 @@ def lstatus(pid, ppid):
         status = (out.strip() == 'wait')
     else:
         return ProcStatus.NOT_STARTED
+
     return ProcStatus.RUNNING if status else ProcStatus.FINISHED
 
 def lkill(pid, ppid, sudo = False):
     """
index 9e6c272..16c7e14 100644 (file)
@@ -29,7 +29,7 @@ class Logger(object):
     def error(self, msg, out = None, err = None):
         self.log(msg, logging.ERROR, out, err)
 
-    def warn(self, msg, out = None, err = None):
+    def warning(self, msg, out = None, err = None):
         self.log(msg, logging.WARNING, out, err)
 
     def info(self, msg, out = None, err = None):
index 8167105..c9ff344 100644 (file)
@@ -220,7 +220,7 @@ class MANIFOLDAPI(object):
         for field in fields:
             if field not in valid_fields:
                 fields.remove(field)
-                #self.warn(" Invalid Manifold field or filter ")
+                #self.warning(" Invalid Manifold field or filter ")
         
         return fields
 
index 23bc509..58cb79b 100644 (file)
@@ -163,4 +163,3 @@ class XMLParser(object):
 
         return box
 
-
diff --git a/src/nepi/util/sfa_api.py b/src/nepi/util/sfa_api.py
deleted file mode 100644 (file)
index f3df754..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-#
-#    NEPI, a framework to manage network experiments
-#    Copyright (C) 2013 INRIA
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
-#         Lucia Guevgeozian Odizzio <lucia.guevgeozian_odizzio@inria.fr>
-
-
-import logging
-import hashlib
-
-from sfa_sfav1 import SFAResourcesParser
-import subprocess
-import warnings
-
-import threading
-
-class SFAApi(object):
-
-    def __init__(self, aggregate = 'ple', slice_id = None, sfi_auth = None, sfi_user = None,
-            sfi_registry = None, sfi_sm = None, timeout = None, private_key = None):
-    
-        self._resources = dict()
-        self._reservable_resources = list()
-        self._leases = dict()
-        self._slice_tags = dict()
-        self._slice_resources = set()
-        self._slice_leases = set()
-        self._aggregate = aggregate
-        self._slice_hrn = slice_id
-        # TODO: take into account Rspec version, SFA V1, GENI V2, GENI V3
-        # For now is SFA V1 from PlanetLab and Nitos (wrong namespace)
-        self._parser = sfa_sfav1.SFAResourcesParser(['ple', 'omf'])
-        self._lock = threading.Lock()
-
-        # Paremeters to contact the XMLRPC SFA service
-        self._sfi_parameters = {'-a': sfi_auth, '-u': sfi_user,
-                '-r': sfi_registry, '-s': sfi_sm, '-t': timeout,
-                '-k': private_key}
-
-        #self._logger = logging.getLogger('nepi.utils.sfiapi')
-        self._fetch_resources_info()
-        self._fetch_slice_info()
-
-    def _sfi_command_options(self):
-        command_options = " ".join("%s %s" % (k,v) for (k,v) in \
-                self._sfi_parameters.iteritems() if v is not None)
-        return command_options
-
-    def _sfi_command_exec(self, command):
-        args = command.split(" ")
-        s = subprocess.Popen(args, stdout = subprocess.PIPE,
-                stdin = subprocess.PIPE)
-        xml, err = s.communicate()
-        if err:
-           raise RuntimeError("Command excecution problem, error: %s", err)
-        return xml
-
-    def _fetch_resources_info(self, resources = True):
-        command_options = self._sfi_command_options()
-        command = "sfi.py " + command_options + " resources -l all"
-        try:
-            xml = self._sfi_command_exec(command)
-        except:
-            #self._logger.error("Error in SFA responds: %s", xml)
-            raise
-        if resources:
-            self._resources, self._leases = self._parser.resources_from_xml(xml, resources = True)
-        else:
-            self._leases = self._parser.resources_from_xml(xml)
-        #self._update_reservable()
-        return xml
-    
-    def _fetch_slice_info(self):
-        command_options = self._sfi_command_options()
-        command = "sfi.py " + command_options + " resources -l all"
-        command = command + " " + self._slice_hrn
-        try:
-            xml = self._sfi_command_exec(command)
-        except:
-            #self._logger.error("Error in SFA responds: %s", xml)
-            raise
-        self._slice_resources, self._slice_leases, self._slice_tags = \
-            self._parser.resources_from_xml(xml, sliver = True, resources = True)
-        return xml
-
-    def _update_reservable(self):
-        for rid, r in self._resources.iteritems():
-            if (r['resource_type'] == 'node' and r['exclusive'].upper() == 'TRUE') \
-                 or (r['resource_type'] == 'channel'):
-                self._reservable_resources.append(rid)
-
-
-    def discover_resources(self, resourceId=None, fields=[], **kwargs):
-        result = dict()
-        resources = self._resources
-
-        if resourceId is not None:
-            resource_ids = resourceId
-            if not isinstance(resource_ids, list):
-                resource_ids = [resource_ids]
-            resources = self._filter_by_resourceId(resources, resource_ids)
-        else:
-            for filter, value in kwargs.items():
-                resources = self._filter_by_filter(resources, filter, value)
-        if not fields:
-            return resources
-        else:
-            for k, info in resources.iteritems():
-                info = self._extract_fields(info, fields)
-                result[k] = info
-            return result
-                
-    def _filter_by_resourceId(self, resources, resource_ids):
-        return dict((k, resources[k]) for k in resource_ids if k in resources)
-
-    def _filter_by_filter(self, resources, filter, value):
-        d = dict()
-        for k in resources.keys():
-            if filter in resources[k]:
-                if resources[k][filter] == value:
-                    d[k] = resources[k]
-        return d
-               
-    def _extract_fields(self, info, fields):
-        return dict((k, info[k]) for k in fields if k in info)
-
-    def discover_fields(self):
-        resources = self._resources
-        fields = []
-        for k, data in resources.iteritems():
-            for field in data:
-                if field not in fields:
-                    fields.append(field)
-        return fields
-
-    def discover_leases(self, resourceId=None):
-        leases = self._leases
-
-        if resourceId is not None:
-            resource_ids = resourceId
-            if not isinstance(resourceId, list):
-                resource_ids = [resource_ids]
-            leases = self._filterbyresourceId(leases, resource_ids)
-        return leases
-
-    def find_resources(self, leases, resources, rtype, quantity, start_time, duration, slot):
-        result = dict()
-        if rtype not in ['node', 'channel']:
-            raise RuntimeError("Unknown type")
-
-        finish_time = start_time + duration * slot
-
-        leases_resources = dict()
-        reservable_resources = dict()
-        for lid, lease in leases.iteritems():
-            if lease[0]['type'] == rtype:
-                leases_resources.update({lid: lease})
-        #print leases_resources
-        for rid, resource in resources.iteritems():
-            if rtype == 'node' and (resource['type'] == 'node' and resource['exclusive'].upper() == 'TRUE'):
-                reservable_resources.update({rid: resource})
-            elif rtype == 'channel':
-                reservable_resources.update({rid: resource})
-            #if resource['type'] == 'rtype' and resources['exclusive'].upper() == 'TRUE':\
-            # (in case adding exclusive tag to channels)
-
-        free_resources = list(set(reservable_resources.keys()) - set(leases_resources.keys()))
-    
-        if len(free_resources) >= quantity:
-            free_resources = free_resources[:quantity]
-            for rid, resource in resources.iteritems():
-                if rid in free_resources:
-                    result[rid] = resource
-            return result
-        else:
-            maybe_free = []
-            new_quan = quantity - len(free_resources)
-            print new_quan
-
-            for lid, lease in leases_resources.iteritems():
-                for l in lease:
-                    st = int(l['start_time'])
-                    ft = st + int(l['duration']) * slot
-                    if (st <= finish_time <= ft) or (st <= start_time <= ft):
-                        if lid in maybe_free:
-                            maybe_free.remove(lid)
-                        break
-                    else:
-                        if lid not in maybe_free:
-                            maybe_free.append(lid)
-                if len(maybe_free) >= new_quan:
-                    free_resources = [free_resources, maybe_free]
-                    free_resources = sum(free_resources, [])
-                    for rid, resource in resources.iteritems():
-                        if rid in free_resources:
-                            result[rid] = resource
-                        return result
-                    #return free_resources
-            warnings.warn("There aren't enough nodes")
-
-                                 
-    def provision_resource(self, new_resource, start_time = None, duration = None):
-        import os, tempfile
-        with self._lock:
-            xml = self._fetch_slice_info()
-            new_xml = self._parser.create_reservation_xml(xml, self._slice_hrn,\
-            new_resource, start_time, duration, self._aggregate)
-            fh, fname = tempfile.mkstemp()
-            print fname
-            os.write(fh, new_xml)
-            os.close(fh)
-            try:
-                command_options = self._sfi_command_options()
-                command = "sfi.py " + command_options + " create %s %s" % (self._slice_hrn, fname)
-                out = self._sfi_command_exec(command)
-            except:
-                raise
-        xml = self._fetch_slice_info()
-        return self._parser.verify_reservation_xml(xml, self._slice_hrn, new_resource, start_time,\
-                duration, self._aggregate)
-
-    def release_resource(self, resource, start_time = None, duration = None):
-        import os, tempfile
-        with self._lock:
-            xml = self._fetch_slice_info()
-            new_xml = self._parser.release_reservation_xml(xml, self._slice_hrn, resource,\
-            start_time, duration, self._aggregate)
-            fh, fname = tempfile.mkstemp()
-            print fname
-            os.write(fh, new_xml)
-            os.close(fh)
-            try:
-                command_options = self._sfi_command_options()
-                command = "sfi.py " + command_options + " create %s %s" % (self._slice_hrn, fname)
-                out = self._sfi_command_exec(command)
-            except:
-                raise
-        xml = self._fetch_slice_info()
-        return not self._parser.verify_reservation_xml(xml, self._slice_hrn, resource, start_time,\
-            duration, self._aggregate)
-
-
-class SFAApiFactory(object):
-    lock = threading.Lock()
-    _apis = dict()
-
-    @classmethod
-    def get_api(slice_id = None, sfi_auth = None, sfi_user = None,
-            sfi_registry = None, sfi_sm = None, timeout = None, private_key = None):
-
-        key = cls.make_key(slice_id, sfi_auth, sfi_user, sfi_registry,
-                           sfi_sm, timeout, private_key, aggregate = 'ple')
-        api = cls._apis.get(key)
-        cls.lock.acquire()
-        api._fetch_resources_info(resources = False)
-        api._fetch_slice_info()
-        cls.lock.release()
-
-        if not api:
-            api = SFAApi(slice_id = None, sfi_auth = None, sfi_user = None,
-            sfi_registry = None, sfi_sm = None, timeout = None, private_key = None)
-            cls._apis[key] = api
-
-        return api
-
-    @classmethod
-    def make_key(cls, *args):
-        skey = "".join(map(str, args))
-        return hashlib.md5(skey).hexdigest()
-
diff --git a/src/nepi/util/sfa_sfav1.py b/src/nepi/util/sfa_sfav1.py
deleted file mode 100644 (file)
index 3d153d1..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-#
-#    NEPI, a framework to manage network experiments
-#    Copyright (C) 2013 INRIA
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
-#         Lucia Guevgeozian Odizzio <lucia.guevgeozian_odizzio@inria.fr>
-
-
-from lxml import etree
-#import collections
-import sys
-
-class SFAResourcesParser(object):
-    # Maybe this init method is not necessary, it was aim to check that the
-    # aggregate was supported by nepi
-
-    def __init__(self, aggr_pattern):
-        if not isinstance(aggr_pattern, list):
-            self._aggr_pattern = [aggr_pattern]
-        else:
-            self._aggr_pattern = aggr_pattern
-    
-    def resources_from_xml(self, xml, sliver = False, resources = False):
-        rdata = dict()
-        ldata = dict()
-        stags = dict()
-        RSpec = etree.fromstring(xml)
-        RSpec_attr = dict(RSpec.attrib)
-        network = RSpec.findall('.//network')
-        for net in network:
-            aggr = net.get('name') 
-            if aggr == 'ple' and resources:
-                node_tree = net.iterfind('node')
-                for node in list(node_tree): 
-                    if isinstance(node.tag, basestring):
-                        data_ple = dict(node.attrib)
-                        data_ple['aggregate'] = aggr
-                        data_ple['resource_type'] = 'node'
-                        data_ple = self._get_node_info(node, data_ple)
-                        hostname = node.find('hostname')
-                        rdata[hostname.text] = data_ple
-                if sliver:
-                    sliver_defaults = net.find('sliver_defaults')
-                    if len(sliver_defaults):
-                        stags = self._get_sliver_tags(sliver_defaults, stags)
-            elif aggr == 'omf' and resources:
-                node_tree = net.iterfind('node')
-                for node in node_tree:
-                    if isinstance(node.tag, basestring):
-                        data_omf = dict(node.attrib)
-                        data_omf['aggregate'] = aggr
-                        data_omf['resource_type'] = 'node'
-                        data_omf = self._get_node_info(node, data_omf)
-                        hostname = node.find('hostname')
-                        rdata[hostname.text] = data_omf
-                spectrum = net.find('spectrum')
-                for channel in list(spectrum):
-                    if isinstance(channel.tag, basestring):
-                        data_omf = dict(channel.attrib)
-                        data_omf['aggregate'] = aggr
-                        data_omf['resource_type'] = 'channel'
-                        channelnum = data_omf['channel_num']
-                        rdata[channelnum] = data_omf
-                leases = net.iterfind('lease')
-                for lease in list(leases):
-                    if isinstance(lease.tag, basestring):
-                        (st, duration) = lease.attrib['start_time'], lease.attrib['duration']
-                        data_lease = dict(lease.attrib)
-                        data_lease['aggregate'] = aggr
-                        data_lease['resource_type'] = 'lease'
-                        data_lease = self._get_leases_info(lease, data_lease)
-                        ldata[(st, duration)] = data_lease
-            elif aggr == 'omf' and not resources:
-                leases = net.iterfind('lease')
-                for lease in list(leases):
-                    if isinstance(lease.tag, basestring):
-                        (st, duration) = lease.attrib['start_time'], lease.attrib['duration']
-                        data_lease = dict(lease.attrib)
-                        data_lease['aggregate'] = aggr
-                        data_lease['resource_type'] = 'lease'
-                        data_lease = self._get_leases_info(lease, data_lease)
-                        ldata[(st, duration)] = data_lease
-            else:
-                pass
-        if sliver:
-            return rdata, ldata, stags
-        elif resources:
-            return rdata, ldata
-        elif not resources:
-            return ldata
-
-    def _get_node_info(self, node_tag, data_dict):
-        for n in list(node_tag):
-            if isinstance(n.tag, basestring):
-                if n.attrib:
-                    data_dict[n.tag] = dict(n.attrib)
-                else:
-                    data_dict[n.tag] = n.text
-        return data_dict
-
-    def _get_leases_info(self, lease_tag, data_dict):
-        nodes = list()
-        channels = list()
-        for l in list(lease_tag):
-            if l.tag == 'node':
-                node = l.attrib['component_id'].split('+').pop()
-                nodes.append(node)
-            if l.tag == 'channel':
-                #TODO: find out key when channel reservation
-                #channels.append(l.attrib['averiguar']) channel_num
-                pass
-            data_dict['nodes'] = nodes
-            data_dict['channels'] = channels
-        return data_dict
-
-    def _get_sliver_tags(self, sliverdefaults_tag, sliver_tag_dict):
-        vsys = list()
-        for info in list(sliverdefaults_tag):
-            if info.tag == 'vsys_vnet':
-                sliver_tag_dict['vsys_vnet'] = info.text
-            elif info.tag == 'vsys':
-                vsys.append(info.text)
-        sliver_tag_dict['vsys'] = vsys
-        return sliver_tag_dict
-            
-    def create_reservation_xml(self, xml, slice_hrn, new_resource, start_time, duration, aggregate):
-        aggrs = []
-        RSpec = etree.fromstring(xml)
-        network = RSpec.findall('.//network')
-        for net in network:
-            aggr = net.get('name')
-            aggrs.append(aggr)
-            if aggr == aggregate:
-                new_xml = self._create_tags(RSpec, net, slice_hrn, new_resource, start_time, duration)
-        if aggregate not in aggrs:
-            new_net = etree.SubElement(RSpec, 'network', name = aggregate)
-            new_xml = self._create_tags(RSpec, new_net, slice_hrn, new_resource, start_time, duration)
-        return new_xml
-
-    def _create_tags(self, RSpec, net, slice_hrn, new_resource, start_time, duration):
-        resource = new_resource.keys()[0]
-        res_type = new_resource[resource]['resource_type']
-        if res_type == 'node':
-            node = etree.SubElement(net, res_type, \
-            component_manager_id = new_resource[resource]['component_manager_id'],\
-            component_id = new_resource[resource]['component_id'],\
-            component_name = new_resource[resource]['component_name'], \
-            site_id = new_resource[resource]['site_id'])
-            sliver_tag = etree.SubElement(node, 'sliver')
-        elif res_type == 'channel':
-            spectrum = etree.SubElement(net, spectrum)
-            channel = etree.SubElement(spectrum, channel,\
-            channel_num = new_resource[resource]['channel_num'],\
-            frequency = new_resource[resource]['frequency'],\
-            standard = new_resource[resource]['standard'])
-        if start_time is not None and duration is not None:
-            slice_id = "urn:publicid:IDN+" + slice_hrn.split('.')[0] + ':' + slice_hrn.split('.')[1]\
-            + '+slice+' + slice_hrn.split('.')[2]
-            lease = etree.SubElement(net, 'lease', slice_id = slice_id,\
-            start_time = str(start_time), duration = str(duration))
-            if res_type == 'node':
-                res = etree.SubElement(lease, res_type,\
-                component_id = new_resource[resource]['component_id'])
-            elif res_type == 'channel':
-                res = etree.SubElement(lease, res_type,\
-                channel_num = new_resource[resource]['channel_num'])
-        new_xml = etree.tostring(RSpec, xml_declaration=True)
-        return new_xml
-                
-    def verify_reservation_xml(self, xml, slice_hrn, new_resource, start_time, duration, aggregate):
-        slice_id = "urn:publicid:IDN+" + slice_hrn.split('.')[0] + ':' + slice_hrn.split('.')[1]\
-        + '+slice+' + slice_hrn.split('.')[2]
-        rdata, ldata, stags = self.resources_from_xml(xml, sliver = True, resources = True)
-        res_name = new_resource.keys()[0]
-        if res_name in rdata.keys():
-            if start_time and duration:
-                if ldata[(start_time, duration)]:
-                    nodes = ldata[(start_time, duration)]['nodes']
-                    sliceid = ldata[(start_time, duration)]['slice_id']
-                    if res_name in nodes and sliceid == slice_id:
-                        return True
-                    else: return False
-                else: return False
-            else: return True
-        else: return False
-
-    def release_reservation_xml(self, xml, slice_hrn, resource, start_time, duration, aggregate):
-        RSpec = etree.fromstring(xml)
-        network = RSpec.findall('.//network')
-        for net in network:
-            aggr = net.get('name')
-            if aggr == aggregate:
-                new_xml = self._delete_tag(RSpec, net, slice_hrn, resource, start_time, duration)
-                return new_xml
-
-    def _delete_tag(self, RSpec, net, slice_hrn, resource, start_time, duration):
-        resource_name = resource.keys()[0]
-        res_type = resource[resource_name]['resource_type']
-        if res_type == 'node':
-            node_tree = net.iterfind('node')
-            for node in list(node_tree):
-                if isinstance(node.tag, basestring):
-                    data_node = dict(node.attrib)
-                    if data_node['component_name'] == resource_name:
-                        net.remove(node)
-        elif res_type == 'channel':
-            spectrum = net.find('spectrum')
-            for channel in list(spectrum):
-                if isinstance(channel.tag, basestring):
-                    data_channel = dict(channel.attrib)
-                    if data_channel['channel_num'] == resource_name:
-                        spectrum.remove(channel)
-        if start_time is not None and duration is not None:
-            slice_id = "urn:publicid:IDN+" + slice_hrn.split('.')[0] + ':' + slice_hrn.split('.')[1]\
-            + '+slice+' + slice_hrn.split('.')[2]
-            leases = net.iterfind('lease')
-            for lease in list(leases):
-                if isinstance(lease.tag, basestring):
-                    (st, duration) = lease.attrib['start_time'], lease.attrib['duration']
-                    sliceid = lease.attrib['slice_id']
-                    if st == str(start_time) and duration == str(duration) and sliceid == slice_id:
-                        for l in list(lease):
-                            if l.tag == 'node' and res_type == 'node':
-                                if l.attrib['component_id'].split('+').pop() == resource_name:
-                                    lease.remove(l)
-                            elif l.tag == 'channel' and res_type == 'channel':
-                                if l.attrib['channel_num'] == resource_name:
-                                    lease.remove(l)
-        new_xml = etree.tostring(RSpec, xml_declaration=True)
-        return new_xml
-
-
diff --git a/src/nepi/util/sfaapi.py b/src/nepi/util/sfaapi.py
new file mode 100644 (file)
index 0000000..d2888fd
--- /dev/null
@@ -0,0 +1,277 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Lucia Guevgeozian Odizzio <lucia.guevgeozian_odizzio@inria.fr>
+
+import threading
+import hashlib
+import re
+import os
+
+from nepi.util.logger import Logger
+
+try:
+    from sfa.client.sfi import Sfi
+    from sfa.util.xrn import hrn_to_urn
+except ImportError:
+    log = Logger("SFA API")
+    log.debug("Packages sfa-common or sfa-client not installed.\
+         Could not import sfa.client.sfi or sfa.util.xrn")
+
+from nepi.util.sfarspec_proc import SfaRSpecProcessing
+
+class SFAAPI(object):
+    """
+    API for quering the SFA service.
+    """
+    def __init__(self, sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec,
+        timeout):
+
+        self._blacklist = set()
+        self._reserved = set()
+        self._resources_cache = None
+        self._already_cached = False
+        self._log = Logger("SFA API")
+        self.api = Sfi()
+        self.rspec_proc = SfaRSpecProcessing()
+        self.lock_slice = threading.Lock()
+        self.lock_blist = threading.Lock()
+        self.lock_resv = threading.Lock()
+
+        self.api.options.timeout = timeout
+        self.api.options.raw = None
+        self.api.options.user = sfi_user
+        self.api.options.auth = sfi_auth
+        self.api.options.registry = sfi_registry
+        self.api.options.sm = sfi_sm
+        self.api.options.user_private_key = private_key
+
+        # Load blacklist from file
+        if ec.get_global('PlanetlabNode', 'persist_blacklist'):
+            self._set_blacklist()
+
+    def _set_blacklist(self):
+        nepi_home = os.path.join(os.path.expanduser("~"), ".nepi")
+        plblacklist_file = os.path.join(nepi_home, "plblacklist.txt")
+        with open(plblacklist_file, 'r') as f:
+            hosts_tobl = f.read().splitlines()
+            if hosts_tobl:
+                for host in hosts_tobl:
+                    self._blacklist.add(host)
+
+    def _sfi_exec_method(self, command, slicename=None, rspec=None, urn=None):
+        """
+        Execute sfi method.
+        """
+        if command in ['describe', 'delete', 'allocate', 'provision']:
+            if not slicename:
+                raise TypeError("The slice hrn is expected for this method %s" % command)
+            if command == 'allocate' and not rspec:
+                raise TypeError("RSpec is expected for this method %s" % command)
+            
+            if command == 'allocate':
+                args_list = [slicename, rspec]
+            elif command == 'delete':
+                args_list = [slicename, urn]
+            else: args_list = [slicename, '-o', '/tmp/rspec_output']
+
+        elif command == 'resources':
+            args_list = ['-o', '/tmp/rspec_output']
+
+        else: raise TypeError("Sfi method not supported")
+
+        self.api.command = command
+        self.api.command_parser = self.api.create_parser_command(self.api.command)
+        (command_options, command_args) = self.api.command_parser.parse_args(args_list)
+        #print "1 %s" % command_options.info
+        #command_options.info = ""
+        #print "2 %s" % command_options.info
+        self.api.command_options = command_options
+        self.api.read_config()
+        self.api.bootstrap()
+
+        self.api.dispatch(command, command_options, command_args)
+        with open("/tmp/rspec_output.rspec", "r") as result_file:
+            result = result_file.read()
+        return result
+
+    def get_resources_info(self):
+        """
+        Get all resources and its attributes from aggregate.
+        """
+        try:
+            rspec_slice = self._sfi_exec_method('resources')
+        except:
+            raise RuntimeError("Fail to list resources")
+   
+        self._resources_cache = self.rspec_proc.parse_sfa_rspec(rspec_slice)
+        self._already_cached = True
+        return self._resources_cache
+
+    def get_resources_hrn(self, resources=None):
+        """
+        Get list of resources hrn, without the resource info.
+        """
+        if not resources:
+            if not self._already_cached:
+                resources = self.get_resources_info()['resource']
+            else:
+                resources = self._resources_cache['resource']
+
+        component_tohrn = dict()
+        for resource in resources:
+            hrn = resource['hrn'].replace('\\', '')
+            component_tohrn[resource['component_name']] = hrn
+
+        return component_tohrn
+            
+    def get_slice_resources(self, slicename):
+        """
+        Get resources and info from slice.
+        """
+        try:
+            with self.lock_slice:
+                rspec_slice = self._sfi_exec_method('describe', slicename)
+        except:
+            raise RuntimeError("Fail to describe resource for slice %s" % slicename)
+
+        result = self.rspec_proc.parse_sfa_rspec(rspec_slice)
+        return result
+
+
+    def add_resource_to_slice(self, slicename, resource_hrn, leases=None):
+        """
+        Get the list of resources' urn, build the rspec string and call the allocate 
+        and provision method.
+        """
+        resources_hrn_new = list()
+        resource_parts = resource_hrn.split('.')
+        resource_hrn = '.'.join(resource_parts[:2]) + '.' + '\\.'.join(resource_parts[2:])
+        resources_hrn_new.append(resource_hrn)
+
+        slice_resources = self.get_slice_resources(slicename)['resource']
+
+        with self.lock_slice:
+            if slice_resources:
+                slice_resources_hrn = self.get_resources_hrn(slice_resources)
+                for s_hrn_key, s_hrn_value in slice_resources_hrn.iteritems():
+                    s_parts = s_hrn_value.split('.')
+                    s_hrn = '.'.join(s_parts[:2]) + '.' + '\\.'.join(s_parts[2:])
+                    resources_hrn_new.append(s_hrn)
+
+            resources_urn = self._get_resources_urn(resources_hrn_new)
+            rspec = self.rspec_proc.build_sfa_rspec(slicename, resources_urn, leases)
+            f = open("/tmp/rspec_input.rspec", "w")
+            f.truncate(0)
+            f.write(rspec)
+            f.close()
+            
+            if not os.path.getsize("/tmp/rspec_input.rspec") > 0:
+                raise RuntimeError("Fail to create rspec file to allocate resource in slice %s" % slicename)
+
+            try:
+                self._sfi_exec_method('allocate', slicename, "/tmp/rspec_input.rspec")
+            except:
+                raise RuntimeError("Fail to allocate resource for slice %s" % slicename)            
+            try:
+                self._sfi_exec_method('provision', slicename) 
+            except:
+                raise RuntimeError("Fail to provision resource for slice %s" % slicename)
+            return True
+
+    def remove_resource_from_slice(self, slicename, resource_hrn, leases=None):
+        """
+        Get the list of resources' urn, build the rspec string and call the allocate 
+        and provision method.
+        """
+        resource_urn = self._get_resources_urn([resource_hrn]).pop()
+        try:
+            self._sfi_exec_method('delete', slicename, urn=resource_urn)
+        except:
+            raise RuntimeError("Fail to delete resource for slice %s" % slicename)
+        return True
+
+
+    def _get_resources_urn(self, resources_hrn):
+        """
+        Builds list of resources' urn based on hrn.
+        """
+        resources_urn = list()
+
+        for resource in resources_hrn:
+            resources_urn.append(hrn_to_urn(resource, 'node'))
+            
+        return resources_urn
+
+    def blacklist_resource(self, resource_hrn):
+        with self.lock_blist:
+            self._blacklist.add(resource_hrn)
+        with self.lock_resv:
+            if resource_hrn in self._reserved:
+                self._reserved.remove(resource_hrn)
+
+    def blacklisted(self, resource_hrn):
+        with self.lock_blist:
+            if resource_hrn in self._blacklist:
+                return True
+        return False
+
+    def reserve_resource(self, resource_hrn):
+        self._reserved.add(resource_hrn)
+
+    def reserved(self, resource_hrn):
+        with self.lock_resv:
+            if resource_hrn in self._reserved:
+                return True
+            else:
+                self.reserve_resource(resource_hrn)
+                return False
+
+class SFAAPIFactory(object):
+    """
+    API Factory to manage a map of SFAAPI instances as key-value pairs, it
+    instanciate a single instance per key. The key represents the same SFA, 
+    credentials.
+    """
+
+    _lock = threading.Lock()
+    _apis = dict()
+
+   
+    @classmethod
+    def get_api(cls, sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec,
+            timeout = None):
+
+        if sfi_user and sfi_sm:
+            key = cls.make_key(sfi_user, sfi_sm)
+            with cls._lock:
+                api = cls._apis.get(key)
+
+                if not api:
+                    api = SFAAPI(sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key,
+                        ec, timeout)
+                    cls._apis[key] = api
+
+                return api
+
+        return None
+
+    @classmethod
+    def make_key(cls, *args):
+        skey = "".join(map(str, args))
+        return hashlib.md5(skey).hexdigest()
+
diff --git a/src/nepi/util/sfarspec_proc.py b/src/nepi/util/sfarspec_proc.py
new file mode 100644 (file)
index 0000000..40c8480
--- /dev/null
@@ -0,0 +1,197 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from nepi.util.logger import Logger
+try:
+    from sfa.rspecs.rspec import RSpec
+    from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn, urn_to_hrn
+except ImportError:
+    log = Logger("SFA RSpec Processing")
+    log.debug("Package sfa-common not installed.\
+         Could not import sfa.rspecs.rspec and sfa.util.xrn")
+
+from types import StringTypes, ListType
+
+
+class SfaRSpecProcessing(object):
+    """
+    Class to process SFA RSpecs, parse the RSpec replies such as Advertisement RSpecs,
+    and build in the case of Request RSpecs.
+    """
+    def __init__(self, config=None):
+        self._log = Logger("SFA RSpec Processing")
+        self.config = config 
+
+    def make_dict_rec(self, obj):
+        if not obj or isinstance(obj, (StringTypes, bool)):
+            return obj
+        if isinstance(obj, list):
+            objcopy = []
+            for x in obj:
+                objcopy.append(self.make_dict_rec(x))
+            return objcopy
+        # We thus suppose we have a child of dict
+        objcopy = {}
+        for k, v in obj.items():
+            objcopy[k] = self.make_dict_rec(v)
+        return objcopy
+
+    def parse_sfa_rspec(self, rspec_string):
+        """
+        Parse the RSpec XML as a string.
+        """
+        # rspec_type and rspec_version should be set in the config of the platform,
+        # we use GENIv3 as default one if not
+        if self.config:
+            if 'rspec_type' and 'rspec_version' in self.config:
+                rspec_version = self.config['rspec_type'] + ' ' + self.config['rspec_version']
+        else:
+            rspec_version = 'GENI 3'
+        self._log.debug(rspec_version)
+        rspec = RSpec(rspec_string, version=rspec_version)
+        
+        try:
+            nodes = rspec.version.get_nodes()
+        except Exception, e:
+            self._log.warn("Could not retrieve nodes in RSpec: %s" % e)
+        try:
+            leases = rspec.version.get_leases()
+        except Exception, e:
+            self._log.warn("Could not retrieve leases in RSpec: %s" % e)
+        try:
+            links = rspec.version.get_links()
+        except Exception, e:
+            self._log.warn("Could not retrieve links in RSpec: %s" % e)
+        try:
+            channels = rspec.version.get_channels()
+        except Exception, e:
+            self._log.warn("Could not retrieve channels in RSpec: %s" % e)
+  
+        resources = [] 
+        # Extend object and Format object field's name
+        for node in nodes:
+            node['type'] = 'node'
+            node['network_hrn'] = Xrn(node['component_id']).authority[0] # network ? XXX
+            node['hrn'] = urn_to_hrn(node['component_id'])[0]
+            node['urn'] = node['component_id']
+            node['hostname'] = node['component_name']
+            node['initscripts'] = node.pop('pl_initscripts')
+            if 'exclusive' in node and node['exclusive']:
+                node['exclusive'] = node['exclusive'].lower() == 'true'
+            # XXX This should use a MAP as before
+            if 'position' in node: # iotlab
+                node['x'] = node['position']['posx']
+                node['y'] = node['position']['posy']
+                node['z'] = node['position']['posz']
+                del node['position']
+            if 'location' in node:
+                if node['location']:
+                    node['latitude'] = node['location']['latitude']
+                    node['longitude'] = node['location']['longitude']
+                del node['location']
+            # Flatten tags
+            if 'tags' in node:
+                if node['tags']:
+                    for tag in node['tags']:
+                        node[tag['tagname']] = tag['value']
+                del node['tags']
+            
+            # We suppose we have children of dict that cannot be serialized
+            # with xmlrpc, let's make dict
+            resources.append(self.make_dict_rec(node))
+        # NOTE a channel is a resource and should not be treated independently
+        #     resource
+        #        |
+        #   +----+------+-------+
+        #   |    |      |       |
+        # node  link  channel  etc.
+        #resources.extend(nodes)
+        #resources.extend(channels)
+        return {'resource': resources, 'lease': leases } 
+#               'channel': channels \
+#               }
+
+    def build_sfa_rspec(self, slice_id, resources, leases):
+        """
+        Build the XML RSpec from list of resources' urns.
+        eg. resources = ["urn:publicid:IDN+ple:modenaple+node+planetlab-1.ing.unimo.it"]
+        """
+        #if isinstance(resources, str):
+        #    resources = eval(resources)
+        # rspec_type and rspec_version should be set in the config of the platform,
+        # we use GENIv3 as default one if not
+        if self.config:
+            if 'rspec_type' and 'rspec_version' in self.config:
+                rspec_version = self.config['rspec_type'] + ' ' + self.config['rspec_version']
+        else:
+            rspec_version = 'GENI 3'
+
+        # extend rspec version with "content_type"
+        rspec_version += ' request'
+        
+        rspec = RSpec(version=rspec_version)
+
+        nodes = []
+        channels = []
+        links = []
+        self._log.info("Building RSpec for resources %s" % resources)
+        for urn in resources:
+            # XXX TO BE CORRECTED, this handles None values
+            if not urn:
+                continue
+            self._log.info(urn)
+            resource = dict()
+            # TODO: take into account the case where we send a dict of URNs without keys
+            #resource['component_id'] = resource.pop('urn')
+            resource['component_id'] = urn
+            resource_hrn, resource_type = urn_to_hrn(resource['component_id'])
+            # build component_manager_id
+            top_auth = resource_hrn.split('.')[0]
+            cm = urn.split("+")
+            resource['component_manager_id'] = "%s+%s+authority+cm" % (cm[0],top_auth)
+
+            if resource_type == 'node':
+                # XXX dirty hack WiLab !!!
+                if self.config:
+                    if 'wilab2' in self.config['sm']:
+                        resource['client_id'] = "PC"
+                        resource['sliver_type'] = "raw-pc"
+                nodes.append(resource)
+            elif resource_type == 'link':
+                links.append(resource)
+            elif resource_type == 'channel':
+                channels.append(resource)
+            else:
+                raise Exception, "Not supported type of resource" 
+        
+        rspec.version.add_nodes(nodes, rspec_content_type="request")
+        #rspec.version.add_leases(leases)
+        #rspec.version.add_links(links)
+        #rspec.version.add_channels(channels)
+   
+        self._log.info("request rspec: %s"%rspec.toxml())
+        return rspec.toxml()
+
+
index d4d02ff..9a416ae 100644 (file)
@@ -18,6 +18,8 @@
 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
 #         Claudio Freire <claudio-daniel.freire@inria.fr>
 
+## TODO: This code needs reviewing !!!
+
 import base64
 import errno
 import hashlib
@@ -44,7 +46,6 @@ def log(msg, level, out = None, err = None):
 
     logger.log(level, msg)
 
-
 if hasattr(os, "devnull"):
     DEV_NULL = os.devnull
 else:
@@ -210,15 +211,12 @@ def rexec(command, host, user,
         gw = None, 
         agent = True,
         sudo = False,
-        stdin = None,
         identity = None,
         server_key = None,
         env = None,
         tty = False,
-        timeout = None,
-        retry = 3,
-        err_on_timeout = True,
         connect_timeout = 30,
+        retry = 3,
         persistent = True,
         forward_x11 = False,
         blocking = True,
@@ -226,7 +224,7 @@ def rexec(command, host, user,
     """
     Executes a remote command, returns ((stdout,stderr),process)
     """
-    
+
     tmp_known_hosts = None
     if not gw:
         hostip = gethostbyname(host)
@@ -266,6 +264,7 @@ def rexec(command, host, user,
         args.append('-p%d' % port)
 
     if identity:
+        identity = os.path.expanduser(identity)
         args.extend(('-i', identity))
 
     if tty:
@@ -285,65 +284,25 @@ def rexec(command, host, user,
 
     args.append(command)
 
-    for x in xrange(retry):
-        # connects to the remote host and starts a remote connection
-        proc = subprocess.Popen(args,
-                env = env,
-                stdout = subprocess.PIPE,
-                stdin = subprocess.PIPE, 
-                stderr = subprocess.PIPE)
-       
-        # attach tempfile object to the process, to make sure the file stays
-        # alive until the process is finished with it
-        proc._known_hosts = tmp_known_hosts
-    
-        # by default, rexec calls _communicate which will block 
-        # until the process has exit. The argument block == False 
-        # forces to rexec to return immediately, without blocking 
-        try:
-            if blocking:
-                out, err = _communicate(proc, stdin, timeout, err_on_timeout)
-            else:
-                err = proc.stderr.read()
-                out = proc.stdout.read()
-
-            msg = " rexec - host %s - command %s " % (host, " ".join(args))
-            log(msg, logging.DEBUG, out, err)
-
-            if proc.poll():
-                skip = False
+    log_msg = " rexec - host %s - command %s " % (str(host), " ".join(map(str, args))) 
 
-                if err.strip().startswith('ssh: ') or err.strip().startswith('mux_client_hello_exchange: '):
-                    # SSH error, can safely retry
-                    skip = True 
-                elif retry:
-                    # Probably timed out or plain failed but can retry
-                    skip = True 
-                
-                if skip:
-                    t = x*2
-                    msg = "SLEEPING %d ... ATEMPT %d - host %s - command %s " % ( 
-                            t, x, host, " ".join(args))
-                    log(msg, logging.DEBUG)
-
-                    time.sleep(t)
-                    continue
-            break
-        except RuntimeError, e:
-            msg = " rexec EXCEPTION - host %s - command %s - TIMEOUT -> %s" % (host, " ".join(args), e.args)
-            log(msg, logging.DEBUG, out, err)
+    stdout = stderr = stdin = subprocess.PIPE
+    if forward_x11:
+        stdout = stderr = stdin = None
 
-            if retry <= 0:
-                raise
-            retry -= 1
-        
-    return ((out, err), proc)
+    return _retry_rexec(args, log_msg, 
+            stderr = stderr,
+            stdin = stdin,
+            stdout = stdout,
+            env = env, 
+            retry = retry, 
+            tmp_known_hosts = tmp_known_hosts,
+            blocking = blocking)
 
 def rcopy(source, dest,
         port = None,
         gwuser = None,
         gw = None,
-        agent = True, 
         recursive = False,
         identity = None,
         server_key = None,
@@ -355,279 +314,80 @@ def rcopy(source, dest,
     Source and destination should have the user and host encoded
     as per scp specs.
     
-    If source is a file object, a special mode will be used to
-    create the remote file with the same contents.
-    
-    If dest is a file object, the remote file (source) will be
-    read and written into dest.
-    
-    In these modes, recursive cannot be True.
-    
-    Source can be a list of files to copy to a single destination,
-    in which case it is advised that the destination be a folder.
+    Source can be a list of files to copy to a single destination, 
+    (in which case it is advised that the destination be a folder),
+    or a single file in a string.
     """
-    
-    if isinstance(source, file) and source.tell() == 0:
-        source = source.name
-    elif hasattr(source, 'read'):
-        tmp = tempfile.NamedTemporaryFile()
-        while True:
-            buf = source.read(65536)
-            if buf:
-                tmp.write(buf)
-            else:
-                break
-        tmp.seek(0)
-        source = tmp.name
-    
-    if isinstance(source, file) or isinstance(dest, file) \
-            or hasattr(source, 'read')  or hasattr(dest, 'write'):
-        assert not recursive
-        
-        # Parse source/destination as <user>@<server>:<path>
-        if isinstance(dest, basestring) and ':' in dest:
-            remspec, path = dest.split(':',1)
-        elif isinstance(source, basestring) and ':' in source:
-            remspec, path = source.split(':',1)
-        else:
-            raise ValueError, "Both endpoints cannot be local"
-        user,host = remspec.rsplit('@',1)
-        
-        tmp_known_hosts = None
-        if not gw:
-            hostip = gethostbyname(host)
-        else: hostip = None
-        
-        args = ['ssh', '-l', user, '-C',
-                # Don't bother with localhost. Makes test easier
-                '-o', 'NoHostAuthenticationForLocalhost=yes',
-                '-o', 'ConnectTimeout=60',
-                '-o', 'ConnectionAttempts=3',
-                '-o', 'ServerAliveInterval=30',
-                '-o', 'TCPKeepAlive=yes',
-                hostip or host ]
-
-        if openssh_has_persist():
-            args.extend([
-                '-o', 'ControlMaster=auto',
-                '-o', 'ControlPath=%s' % (make_control_path(agent, False),),
-                '-o', 'ControlPersist=60' ])
 
-        if gw:
-            if gwuser:
-                proxycommand = 'ProxyCommand=ssh %s@%s -W %%h:%%p' % (gwuser, gw)
-            else:
-                proxycommand = 'ProxyCommand=ssh %%r@%s -W %%h:%%p' % gw
-            args.extend(['-o', proxycommand])
-
-        if port:
-            args.append('-P%d' % port)
-
-        if identity:
-            args.extend(('-i', identity))
-
-        if server_key:
-            # Create a temporary server key file
-            tmp_known_hosts = make_server_key_args(server_key, host, port)
-            args.extend(['-o', 'UserKnownHostsFile=%s' % (tmp_known_hosts.name,)])
-        
-        if isinstance(source, file) or hasattr(source, 'read'):
-            args.append('cat > %s' % (shell_escape(path),))
-        elif isinstance(dest, file) or hasattr(dest, 'write'):
-            args.append('cat %s' % (shell_escape(path),))
-        else:
-            raise AssertionError, "Unreachable code reached! :-Q"
-        
-        # connects to the remote host and starts a remote connection
-        if isinstance(source, file):
-            proc = subprocess.Popen(args, 
-                    stdout = open('/dev/null','w'),
-                    stderr = subprocess.PIPE,
-                    stdin = source)
-            err = proc.stderr.read()
-            proc._known_hosts = tmp_known_hosts
-            eintr_retry(proc.wait)()
-            return ((None,err), proc)
-        elif isinstance(dest, file):
-            proc = subprocess.Popen(args, 
-                    stdout = open('/dev/null','w'),
-                    stderr = subprocess.PIPE,
-                    stdin = source)
-            err = proc.stderr.read()
-            proc._known_hosts = tmp_known_hosts
-            eintr_retry(proc.wait)()
-            return ((None,err), proc)
-        elif hasattr(source, 'read'):
-            # file-like (but not file) source
-            proc = subprocess.Popen(args, 
-                    stdout = open('/dev/null','w'),
-                    stderr = subprocess.PIPE,
-                    stdin = subprocess.PIPE)
-            
-            buf = None
-            err = []
-            while True:
-                if not buf:
-                    buf = source.read(4096)
-                if not buf:
-                    #EOF
-                    break
-                
-                rdrdy, wrdy, broken = select.select(
-                    [proc.stderr],
-                    [proc.stdin],
-                    [proc.stderr,proc.stdin])
-                
-                if proc.stderr in rdrdy:
-                    # use os.read for fully unbuffered behavior
-                    err.append(os.read(proc.stderr.fileno(), 4096))
-                
-                if proc.stdin in wrdy:
-                    proc.stdin.write(buf)
-                    buf = None
-                
-                if broken:
-                    break
-            proc.stdin.close()
-            err.append(proc.stderr.read())
-                
-            proc._known_hosts = tmp_known_hosts
-            eintr_retry(proc.wait)()
-            return ((None,''.join(err)), proc)
-        elif hasattr(dest, 'write'):
-            # file-like (but not file) dest
-            proc = subprocess.Popen(args, 
-                    stdout = subprocess.PIPE,
-                    stderr = subprocess.PIPE,
-                    stdin = open('/dev/null','w'))
-            
-            buf = None
-            err = []
-            while True:
-                rdrdy, wrdy, broken = select.select(
-                    [proc.stderr, proc.stdout],
-                    [],
-                    [proc.stderr, proc.stdout])
-                
-                if proc.stderr in rdrdy:
-                    # use os.read for fully unbuffered behavior
-                    err.append(os.read(proc.stderr.fileno(), 4096))
-                
-                if proc.stdout in rdrdy:
-                    # use os.read for fully unbuffered behavior
-                    buf = os.read(proc.stdout.fileno(), 4096)
-                    dest.write(buf)
-                    
-                    if not buf:
-                        #EOF
-                        break
-                
-                if broken:
-                    break
-            err.append(proc.stderr.read())
-                
-            proc._known_hosts = tmp_known_hosts
-            eintr_retry(proc.wait)()
-            return ((None,''.join(err)), proc)
-        else:
-            raise AssertionError, "Unreachable code reached! :-Q"
+    # Parse destination as <user>@<server>:<path>
+    if isinstance(dest, str) and ':' in dest:
+        remspec, path = dest.split(':',1)
+    elif isinstance(source, str) and ':' in source:
+        remspec, path = source.split(':',1)
     else:
-        # Parse destination as <user>@<server>:<path>
-        if isinstance(dest, basestring) and ':' in dest:
-            remspec, path = dest.split(':',1)
-        elif isinstance(source, basestring) and ':' in source:
-            remspec, path = source.split(':',1)
-        else:
-            raise ValueError, "Both endpoints cannot be local"
-        user,host = remspec.rsplit('@',1)
-        
-        # plain scp
-        tmp_known_hosts = None
-
-        args = ['scp', '-q', '-p', '-C',
-                # Speed up transfer using blowfish cypher specification which is 
-                # faster than the default one (3des)
-                '-c', 'blowfish',
-                # Don't bother with localhost. Makes test easier
-                '-o', 'NoHostAuthenticationForLocalhost=yes',
-                '-o', 'ConnectTimeout=60',
-                '-o', 'ConnectionAttempts=3',
-                '-o', 'ServerAliveInterval=30',
-                '-o', 'TCPKeepAlive=yes' ]
-                
-        if port:
-            args.append('-P%d' % port)
+        raise ValueError, "Both endpoints cannot be local"
+    user,host = remspec.rsplit('@',1)
+    
+    # plain scp
+    tmp_known_hosts = None
 
-        if gw:
-            if gwuser:
-                proxycommand = 'ProxyCommand=ssh %s@%s -W %%h:%%p' % (gwuser, gw)
-            else:
-                proxycommand = 'ProxyCommand=ssh %%r@%s -W %%h:%%p' % gw
-            args.extend(['-o', proxycommand])
+    args = ['scp', '-q', '-p', '-C',
+            # Speed up transfer using blowfish cypher specification which is 
+            # faster than the default one (3des)
+            '-c', 'blowfish',
+            # Don't bother with localhost. Makes test easier
+            '-o', 'NoHostAuthenticationForLocalhost=yes',
+            '-o', 'ConnectTimeout=60',
+            '-o', 'ConnectionAttempts=3',
+            '-o', 'ServerAliveInterval=30',
+            '-o', 'TCPKeepAlive=yes' ]
+            
+    if port:
+        args.append('-P%d' % port)
 
-        if recursive:
-            args.append('-r')
+    if gw:
+        if gwuser:
+            proxycommand = 'ProxyCommand=ssh %s@%s -W %%h:%%p' % (gwuser, gw)
+        else:
+            proxycommand = 'ProxyCommand=ssh %%r@%s -W %%h:%%p' % gw
+        args.extend(['-o', proxycommand])
 
-        if identity:
-            args.extend(('-i', identity))
+    if recursive:
+        args.append('-r')
 
-        if server_key:
-            # Create a temporary server key file
-            tmp_known_hosts = make_server_key_args(server_key, host, port)
-            args.extend(['-o', 'UserKnownHostsFile=%s' % (tmp_known_hosts.name,)])
+    if identity:
+        identity = os.path.expanduser(identity)
+        args.extend(('-i', identity))
 
-        if not strict_host_checking:
-            # Do not check for Host key. Unsafe.
-            args.extend(['-o', 'StrictHostKeyChecking=no'])
+    if server_key:
+        # Create a temporary server key file
+        tmp_known_hosts = make_server_key_args(server_key, host, port)
+        args.extend(['-o', 'UserKnownHostsFile=%s' % (tmp_known_hosts.name,)])
 
-        if isinstance(source,list):
-            args.extend(source)
-        else:
-            if openssh_has_persist():
-                args.extend([
-                    '-o', 'ControlMaster=auto',
-                    '-o', 'ControlPath=%s' % (make_control_path(agent, False),)
-                    ])
-            args.append(source)
+    if not strict_host_checking:
+        # Do not check for Host key. Unsafe.
+        args.extend(['-o', 'StrictHostKeyChecking=no'])
+    
+    if isinstance(source, list):
+        args.extend(source)
+    else:
+        if openssh_has_persist():
+            args.extend([
+                '-o', 'ControlMaster=auto',
+                '-o', 'ControlPath=%s' % (make_control_path(False, False),)
+                ])
+        args.append(source)
 
+    if isinstance(dest, list):
+        args.extend(dest)
+    else:
         args.append(dest)
-        
-        for x in xrange(retry):
-            # connects to the remote host and starts a remote connection
-            proc = subprocess.Popen(args,
-                    stdout = subprocess.PIPE,
-                    stdin = subprocess.PIPE, 
-                    stderr = subprocess.PIPE)
-            
-            # attach tempfile object to the process, to make sure the file stays
-            # alive until the process is finished with it
-            proc._known_hosts = tmp_known_hosts
-        
-            try:
-                (out, err) = proc.communicate()
-                eintr_retry(proc.wait)()
-                msg = " rcopy - host %s - command %s " % (host, " ".join(args))
-                log(msg, logging.DEBUG, out, err)
-
-                if proc.poll():
-                    t = x*2
-                    msg = "SLEEPING %d ... ATEMPT %d - host %s - command %s " % ( 
-                            t, x, host, " ".join(args))
-                    log(msg, logging.DEBUG)
 
-                    time.sleep(t)
-                    continue
-
-                break
-            except RuntimeError, e:
-                msg = " rcopy EXCEPTION - host %s - command %s - TIMEOUT -> %s" % (host, " ".join(args), e.args)
-                log(msg, logging.DEBUG, out, err)
-
-                if retry <= 0:
-                    raise
-                retry -= 1
-            
-        return ((out, err), proc)
+    log_msg = " rcopy - host %s - command %s " % (str(host), " ".join(map(str, args)))
+    
+    return _retry_rexec(args, log_msg, env = None, retry = retry, 
+            tmp_known_hosts = tmp_known_hosts,
+            blocking = True)
 
 def rspawn(command, pidfile, 
         stdout = '/dev/null', 
@@ -901,15 +661,85 @@ fi
 
     return (out, err), proc
 
+def _retry_rexec(args,
+        log_msg,
+        stdout = subprocess.PIPE,
+        stdin = subprocess.PIPE, 
+        stderr = subprocess.PIPE,
+        env = None,
+        retry = 3,
+        tmp_known_hosts = None,
+        blocking = True):
+
+    for x in xrange(retry):
+        # connects to the remote host and starts a remote connection
+        proc = subprocess.Popen(args,
+                env = env,
+                stdout = stdout,
+                stdin = stdin, 
+                stderr = stderr)
+        
+        # attach tempfile object to the process, to make sure the file stays
+        # alive until the process is finished with it
+        proc._known_hosts = tmp_known_hosts
+    
+        # The argument block == False forces to rexec to return immediately, 
+        # without blocking 
+        try:
+            err = out = " "
+            if blocking:
+                #(out, err) = proc.communicate()
+                # The method communicate was re implemented for performance issues
+                # when using python subprocess communicate method the ssh commands 
+                # last one minute each
+                out, err = _communicate(proc, input=None)
+
+            elif stdout:
+                out = proc.stdout.read()
+                if proc.poll() and stderr:
+                    err = proc.stderr.read()
+
+            log(log_msg, logging.DEBUG, out, err)
+
+            if proc.poll():
+                skip = False
+
+                if err.strip().startswith('ssh: ') or err.strip().startswith('mux_client_hello_exchange: '):
+                    # SSH error, can safely retry
+                    skip = True 
+                elif retry:
+                    # Probably timed out or plain failed but can retry
+                    skip = True 
+                
+                if skip:
+                    t = x*2
+                    msg = "SLEEPING %d ... ATEMPT %d - command %s " % ( 
+                            t, x, " ".join(args))
+                    log(msg, logging.DEBUG)
+
+                    time.sleep(t)
+                    continue
+            break
+        except RuntimeError, e:
+            msg = " rexec EXCEPTION - TIMEOUT -> %s \n %s" % ( e.args, log_msg )
+            log(msg, logging.DEBUG, out, err)
+
+            if retry <= 0:
+                raise
+            retry -= 1
+
+    return ((out, err), proc)
+
 # POSIX
+# Don't remove. The method communicate was re implemented for performance issues
 def _communicate(proc, input, timeout=None, err_on_timeout=True):
     read_set = []
     write_set = []
     stdout = None # Return
     stderr = None # Return
-    
+
     killed = False
-    
+
     if timeout is not None:
         timelimit = time.time() + timeout
         killtime = timelimit + 4
@@ -950,10 +780,10 @@ def _communicate(proc, input, timeout=None, err_on_timeout=True):
                 select_timeout = timelimit - curtime + 0.1
         else:
             select_timeout = 1.0
-        
+
         if select_timeout > 1.0:
             select_timeout = 1.0
-            
+
         try:
             rlist, wlist, xlist = select.select(read_set, write_set, [], select_timeout)
         except select.error,e:
@@ -961,7 +791,7 @@ def _communicate(proc, input, timeout=None, err_on_timeout=True):
                 raise
             else:
                 continue
-        
+
         if not rlist and not wlist and not xlist and proc.poll() is not None:
             # timeout and process exited, say bye
             break
@@ -991,7 +821,7 @@ def _communicate(proc, input, timeout=None, err_on_timeout=True):
                 proc.stderr.close()
                 read_set.remove(proc.stderr)
             stderr.append(data)
-    
+
     # All data exchanged.  Translate lists into strings.
     if stdout is not None:
         stdout = ''.join(stdout)
@@ -1018,3 +848,4 @@ def _communicate(proc, input, timeout=None, err_on_timeout=True):
             proc.wait()
         return (stdout, stderr)
 
+
index 1a8e102..3d7c366 100644 (file)
@@ -56,13 +56,16 @@ def tdiff(date1, date2):
     """
     return date1 - date2
 
+def _get_total_seconds(td): 
+    return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 1e6) / 1e6
+
 def tdiffsec(date1, date2):
     """ Returns the date difference ( date1 - date2 ) in seconds,
     where date1 and date 2 are datetime objects 
     
     """
     diff = tdiff(date1, date2)
-    return diff.total_seconds()
+    return _get_total_seconds(diff)
 
 def stabsformat(sdate, dbase = None):
     """ Constructs a datetime object from a string date.
index 447c703..1940552 100644 (file)
@@ -20,6 +20,7 @@
 from nepi.resources.linux.node import LinuxNode
 
 import os
+import sys
 
 class DummyEC(object):
     @property
@@ -96,3 +97,28 @@ def skipIfNotPLCredentials(func):
 
     return wrapped
 
+def skipIfNotPythonVersion(func):
+    name = func.__name__
+    def wrapped(*args, **kwargs):
+        if sys.version_info < 2.7:
+            print "*** WARNING: Skipping test %s: total_seconds() method doesn't exist\n" % name
+            return
+
+        return func(*args, **kwargs)
+
+    return wrapped
+
+def skipIfNotSfaCredentials(func):
+    name = func.__name__
+    def wrapped(*args, **kwargs):
+        sfa_user = os.environ.get("SFA_USER")
+        sfa_pk = os.environ.get("SFA_PK")
+        
+        if not (sfa_user and os.path.exists(os.path.expanduser(sfa_pk))):
+            print "*** WARNING: Skipping test %s: SFA path to private key doesn't exist\n" % name
+            return
+
+        return func(*args, **kwargs)
+
+    return wrapped
+
index edbc2ba..a1f1397 100755 (executable)
@@ -25,6 +25,7 @@ from nepi.execution.trace import TraceAttr
 from test_utils import skipIfNotAlive, skipInteractive
 
 import os
+import shutil
 import time
 import tempfile
 import unittest
@@ -32,10 +33,10 @@ import unittest
 class LinuxApplicationTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
-        self.ubuntu_user = "alina"
+        self.ubuntu_user = "inria_nepi"
         
         self.target = "nepi5.pl.sophia.inria.fr"
 
@@ -238,12 +239,15 @@ main (void)
         ec.set(node, "cleanHome", True)
         ec.set(node, "cleanProcesses", True)
 
-        sources = "http://yans.pl.sophia.inria.fr/code/nef/archive/tip.tar.gz " \
-                " http://yans.pl.sophia.inria.fr/code/nef/raw-file/8ace577d4079/src/nef/images/menu/connect.png"
+        sources = "http://yans.pl.sophia.inria.fr/code/nef/archive/tip.tar.gz;" \
+                "http://yans.pl.sophia.inria.fr/code/nef/raw-file/8ace577d4079/src/nef/images/menu/connect.png"
 
         app = ec.register_resource("LinuxApplication")
         ec.set(app, "sources", sources)
 
+        command = "ls ${SRC}"
+        ec.set(app, "command", command)
+
         ec.register_connection(app, node)
 
         ec.deploy()
@@ -260,6 +264,10 @@ main (void)
         self.assertTrue(out.find("tip.tar.gz") > -1)
         self.assertTrue(out.find("connect.png") > -1)
 
+        stdout = ec.trace(app, "stdout")
+        self.assertTrue(stdout.find("tip.tar.gz") > -1)
+        self.assertTrue(stdout.find("connect.png") > -1)
+
         ec.shutdown()
 
     @skipIfNotAlive
@@ -288,6 +296,44 @@ main (void)
 
         ec.shutdown()
 
+    @skipIfNotAlive
+    def t_copy_files(self, host, user):
+        # create some temp files and directories to copy
+        dirpath = tempfile.mkdtemp()
+        f = tempfile.NamedTemporaryFile(dir=dirpath, delete=False)
+        f.close()
+      
+        f1 = tempfile.NamedTemporaryFile(delete=False)
+        f1.close()
+        f1.name
+
+        ec = ExperimentController(exp_id="test-copyfile")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", host)
+        ec.set(node, "username", user)
+        ec.set(node, "cleanHome", True)
+        ec.set(node, "cleanProcesses", True)
+
+        app = ec.register_resource("LinuxApplication")
+        ec.set(app, "command", "ls ${SRC}")
+        ec.set(app, "sources", "%s;%s" % (dirpath, f1.name))
+        ec.register_connection(app, node)
+
+        ec.deploy()
+
+        ec.wait_finished([app])
+
+        stdout = ec.trace(app, "stdout")
+        
+        self.assertTrue(stdout.find(os.path.basename(dirpath)) > -1)
+        self.assertTrue(stdout.find(os.path.basename(f1.name)) > -1)
+
+        ec.shutdown()
+        
+        os.remove(f1.name)
+        shutil.rmtree(dirpath)
+
     def test_stdout_fedora(self):
         self.t_stdout(self.fedora_host, self.fedora_user)
 
@@ -329,6 +375,11 @@ main (void)
         """ Interactive test. Should not run automatically """
         self.t_xterm(self.ubuntu_host, self.ubuntu_user)
 
+    def test_copy_files_fedora(self):
+        self.t_copy_files(self.fedora_host, self.fedora_user)
+
+    def test_copy_files_ubuntu(self):
+        self.t_copy_files(self.ubuntu_host, self.ubuntu_user)
 
 if __name__ == '__main__':
     unittest.main()
index 672a11c..a740128 100644 (file)
@@ -29,7 +29,7 @@ import unittest
 class LinuxCCNPingTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
         self.ubuntu_user = "alina"
index 00ac5e8..c6b219c 100644 (file)
@@ -29,7 +29,7 @@ import unittest
 class LinuxFIBEntryTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
         self.ubuntu_user = "nepi"
index bd4d74d..379f92e 100755 (executable)
@@ -35,7 +35,7 @@ import unittest
 class LinuxInterfaceTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
         self.ubuntu_user = "alina"
index c62848a..a34068d 100755 (executable)
@@ -29,7 +29,7 @@ import unittest
 class LinuxMtrTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
         self.ubuntu_user = "alina"
index cebf0d8..e46f667 100755 (executable)
@@ -24,6 +24,7 @@ from nepi.util.sshfuncs import ProcStatus
 
 from test_utils import skipIfNotAlive, skipInteractive, create_node
 
+import shutil
 import os
 import time
 import tempfile
@@ -32,10 +33,10 @@ import unittest
 class LinuxNodeTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
-        self.ubuntu_user = "alina"
+        self.ubuntu_user = "inria_nepi"
         
         self.target = "nepi5.pl.sophia.inria.fr"
 
@@ -213,7 +214,6 @@ class LinuxNodeTestCase(unittest.TestCase):
 
         self.assertEquals(out.strip(), "")
 
-
     @skipIfNotAlive
     def t_xterm(self, host, user):
         node, ec = create_node(host, user)
@@ -286,6 +286,55 @@ main (void)
         
         self.assertEquals(out, "Hello, world!\n")
 
+    @skipIfNotAlive
+    def t_copy_files(self, host, user):
+        node, ec = create_node(host, user)
+
+        node.find_home()
+        app_home = os.path.join(node.exp_home, "my-app")
+        node.mkdir(app_home, clean = True)
+
+        # create some temp files and directories to copy
+        dirpath = tempfile.mkdtemp()
+        f = tempfile.NamedTemporaryFile(dir=dirpath, delete=False)
+        f.close()
+      
+        f1 = tempfile.NamedTemporaryFile(delete=False)
+        f1.close()
+        f1.name
+
+        source = [dirpath, f1.name]
+        destdir = "test"
+        node.mkdir(destdir, clean = True)
+        dest = "%s@%s:test" % (user, host)
+        node.copy(source, dest)
+
+        command = "ls %s" % destdir
+        
+        (out, err), proc = node.execute(command)
+
+        os.remove(f1.name)
+        shutil.rmtree(dirpath)
+
+        self.assertTrue(out.find(os.path.basename(dirpath)) > -1)
+        self.assertTrue(out.find(os.path.basename(f1.name)) > -1)
+
+        f2 = tempfile.NamedTemporaryFile(delete=False)
+        f2.close()
+        f2.name
+
+        node.mkdir(destdir, clean = True)
+        dest = "%s@%s:test" % (user, host)
+        node.copy(f2.name, dest)
+
+        command = "ls %s" % destdir
+        
+        (out, err), proc = node.execute(command)
+
+        os.remove(f2.name)
+        
+        self.assertTrue(out.find(os.path.basename(f2.name)) > -1)
+
     def test_execute_fedora(self):
         self.t_execute(self.fedora_host, self.fedora_user)
 
@@ -339,6 +388,11 @@ main (void)
         """ Interactive test. Should not run automatically """
         self.t_xterm(self.ubuntu_host, self.ubuntu_user)
 
+    def test_copy_files_fedora(self):
+        self.t_copy_files(self.fedora_host, self.fedora_user)
+
+    def test_copy_files_ubuntu(self):
+        self.t_copy_files(self.ubuntu_host, self.ubuntu_user)
 
 if __name__ == '__main__':
     unittest.main()
index b6af3dc..19c4ef4 100755 (executable)
@@ -29,7 +29,7 @@ import unittest
 class LinuxNPingTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
         self.ubuntu_user = "alina"
diff --git a/test/resources/linux/ns3/ns-3.18-user.tar.gz b/test/resources/linux/ns3/ns-3.18-user.tar.gz
new file mode 100644 (file)
index 0000000..fcbfb70
Binary files /dev/null and b/test/resources/linux/ns3/ns-3.18-user.tar.gz differ
diff --git a/test/resources/linux/ns3/ns3client.py b/test/resources/linux/ns3/ns3client.py
new file mode 100644 (file)
index 0000000..8fad928
--- /dev/null
@@ -0,0 +1,200 @@
+#!/usr/bin/env python
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+
+# Test based on ns-3 csma/examples/csma-ping.cc file
+#
+# Network topology
+#
+#       n0    n1   n2   n3
+#       |     |    |    |
+#       -----------------
+#
+#  node n0 sends IGMP traffic to node n3
+
+
+from nepi.resources.ns3.ns3server import run_server
+from nepi.resources.linux.ns3.ns3client import LinuxNS3Client
+
+import os
+import threading
+import time
+import unittest
+
+class DummySimulation(object):
+    def __init__(self, socket_name):
+        self.socket_name = socket_name
+        self.node = dict({'hostname': 'localhost'})
+
+    @property
+    def remote_socket(self):
+        return self.socket_name
+
+class LinuxNS3ClientTest(unittest.TestCase):
+    def setUp(self):
+        self.socket_name = os.path.join("/", "tmp", "NS3WrapperServer.sock")
+        if os.path.exists(self.socket_name):
+            os.remove(self.socket_name) 
+
+    def tearDown(self):
+        os.remove(self.socket_name) 
+
+    def test_runtime_attr_modify(self):
+        thread = threading.Thread(target = run_server,
+                args = [self.socket_name])
+
+        thread.setDaemon(True)
+        thread.start()
+
+        time.sleep(3)
+
+        # Verify that the communication socket was created
+        self.assertTrue(os.path.exists(self.socket_name))
+
+        # Create a dummy simulation object
+        simulation = DummySimulation(self.socket_name) 
+
+        # Instantiate the NS3 client
+        client = LinuxNS3Client(simulation)
+        # Define a real time simulation 
+        stype = client.create("StringValue", "ns3::RealtimeSimulatorImpl")
+        client.invoke("singleton::GlobalValue", "Bind", "SimulatorImplementationType", stype)
+        btrue = client.create("BooleanValue", True)
+        client.invoke("singleton::GlobalValue", "Bind", "ChecksumEnabled", btrue)
+        
+        # Create Node
+        n1 = client.create("Node")
+        self.assertTrue(n1.startswith("uuid"))
+
+        ## Install internet stack
+        ipv41 = client.create("Ipv4L3Protocol")
+        client.invoke(n1, "AggregateObject", ipv41)
+
+        arp1 = client.create("ArpL3Protocol")
+        client.invoke(n1, "AggregateObject", arp1)
+        
+        icmp1 = client.create("Icmpv4L4Protocol")
+        client.invoke(n1, "AggregateObject", icmp1)
+
+        ## Add IPv4 routing
+        lr1 = client.create("Ipv4ListRouting")
+        client.invoke(ipv41, "SetRoutingProtocol", lr1)
+        sr1 = client.create("Ipv4StaticRouting")
+        client.invoke(lr1, "AddRoutingProtocol", sr1, 1)
+
+        ## NODE 2
+        n2 = client.create("Node")
+
+        ## Install internet stack
+        ipv42 = client.create("Ipv4L3Protocol")
+        client.invoke(n2, "AggregateObject", ipv42)
+
+        arp2 = client.create("ArpL3Protocol")
+        client.invoke(n2, "AggregateObject", arp2)
+        
+        icmp2 = client.create("Icmpv4L4Protocol")
+        client.invoke(n2, "AggregateObject", icmp2)
+
+        ## Add IPv4 routing
+        lr2 = client.create("Ipv4ListRouting")
+        client.invoke(ipv42, "SetRoutingProtocol", lr2)
+        sr2 = client.create("Ipv4StaticRouting")
+        client.invoke(lr2, "AddRoutingProtocol", sr2, 1)
+
+        ##### Create p2p device and enable ascii tracing
+        p2pHelper = client.create("PointToPointHelper")
+        asciiHelper = client.create("AsciiTraceHelper")
+
+        # Iface for node1
+        p1 = client.create("PointToPointNetDevice")
+        client.invoke(n1, "AddDevice", p1)
+        q1 = client.create("DropTailQueue")
+        client.invoke(p1, "SetQueue", q1)
+      
+        # Add IPv4 address
+        ifindex1 = client.invoke(ipv41, "AddInterface", p1)
+        mask1 = client.create("Ipv4Mask", "/30")
+        addr1 = client.create("Ipv4Address", "10.0.0.1")
+        inaddr1 = client.create("Ipv4InterfaceAddress", addr1, mask1)
+        client.invoke(ipv41, "AddAddress", ifindex1, inaddr1)
+        client.invoke(ipv41, "SetMetric", ifindex1, 1)
+        client.invoke(ipv41, "SetUp", ifindex1)
+
+        # Enable collection of Ascii format to a specific file
+        filepath1 = "trace-p2p-1.tr"
+        stream1 = client.invoke(asciiHelper, "CreateFileStream", filepath1)
+        client.invoke(p2pHelper, "EnableAscii", stream1, p1)
+       
+        # Iface for node2
+        p2 = client.create("PointToPointNetDevice")
+        client.invoke(n2, "AddDevice", p2)
+        q2 = client.create("DropTailQueue")
+        client.invoke(p2, "SetQueue", q2)
+
+        # Add IPv4 address
+        ifindex2 = client.invoke(ipv42, "AddInterface", p2)
+        mask2 = client.create("Ipv4Mask", "/30")
+        addr2 = client.create("Ipv4Address", "10.0.0.2")
+        inaddr2 = client.create("Ipv4InterfaceAddress", addr2, mask2)
+        client.invoke(ipv42, "AddAddress", ifindex2, inaddr2)
+        client.invoke(ipv42, "SetMetric", ifindex2, 1)
+        client.invoke(ipv42, "SetUp", ifindex2)
+
+        # Enable collection of Ascii format to a specific file
+        filepath2 = "trace-p2p-2.tr"
+        stream2 = client.invoke(asciiHelper, "CreateFileStream", filepath2)
+        client.invoke(p2pHelper, "EnableAscii", stream2, p2)
+
+        # Create channel
+        chan = client.create("PointToPointChannel")
+        client.set(chan, "Delay", "0s")
+        client.invoke(p1, "Attach", chan)
+        client.invoke(p2, "Attach", chan)
+
+        ### create pinger
+        ping = client.create("V4Ping")
+        client.invoke(n1, "AddApplication", ping)
+        client.set (ping, "Remote", "10.0.0.2")
+        client.set (ping, "Interval", "1s")
+        client.set (ping, "Verbose", True)
+        client.set (ping, "StartTime", "0s")
+        client.set (ping, "StopTime", "20s")
+
+        ### run Simulation
+        client.stop(time = "21s")
+        client.start()
+
+        time.sleep(1)
+
+        client.set(chan, "Delay", "5s")
+
+        time.sleep(5)
+
+        client.set(chan, "Delay", "0s")
+
+        # wait until simulation is over
+        client.shutdown()
+
+        ## TODO: Add assertions !!
+
+if __name__ == '__main__':
+    unittest.main()
+
diff --git a/test/resources/linux/ns3/ns3dceapplication.py b/test/resources/linux/ns3/ns3dceapplication.py
new file mode 100644 (file)
index 0000000..a4901ae
--- /dev/null
@@ -0,0 +1,370 @@
+#!/usr/bin/env python
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+
+from nepi.execution.ec import ExperimentController 
+from nepi.execution.trace import TraceAttr
+
+import os
+import time
+import unittest
+
+def add_ns3_node(ec, simu):
+    node = ec.register_resource("ns3::Node")
+    ec.register_connection(node, simu)
+
+    ipv4 = ec.register_resource("ns3::Ipv4L3Protocol")
+    ec.register_connection(node, ipv4)
+
+    arp = ec.register_resource("ns3::ArpL3Protocol")
+    ec.register_connection(node, arp)
+    
+    icmp = ec.register_resource("ns3::Icmpv4L4Protocol")
+    ec.register_connection(node, icmp)
+
+    udp = ec.register_resource("ns3::UdpL4Protocol")
+    ec.register_connection(node, udp)
+
+    return node
+
+def add_point2point_device(ec, node, address = None,  prefix = None):
+    dev = ec.register_resource("ns3::PointToPointNetDevice")
+    if address:
+       ec.set(dev, "ip", address)
+    if prefix:
+       ec.set(dev, "prefix", prefix)
+    ec.register_connection(node, dev)
+
+    queue = ec.register_resource("ns3::DropTailQueue")
+    ec.register_connection(dev, queue)
+
+    return dev
+
+def add_csma_device(ec, node, address = None, prefix = None):
+    dev = ec.register_resource("ns3::CsmaNetDevice")
+    if address:
+        ec.set(dev, "ip", address)
+    if prefix:
+        ec.set(dev, "prefix", prefix)
+    ec.register_connection(node, dev)
+
+    queue = ec.register_resource("ns3::DropTailQueue")
+    ec.register_connection(dev, queue)
+
+    return dev
+
+def add_wifi_device(ec, node, address = None, prefix = None, 
+        access_point = False):
+    dev = ec.register_resource("ns3::WifiNetDevice")
+    if address:
+        ec.set(dev, "ip", address)
+    if prefix:
+        ec.set(dev, "prefix", prefix)
+    ec.register_connection(node, dev)
+
+    phy = ec.register_resource("ns3::YansWifiPhy")
+    ec.set(phy, "Standard", "WIFI_PHY_STANDARD_80211a")
+    ec.register_connection(dev, phy)
+
+    error = ec.register_resource("ns3::NistErrorRateModel")
+    ec.register_connection(phy, error)
+
+    manager = ec.register_resource("ns3::ArfWifiManager")
+    ec.register_connection(dev, manager)
+
+    if access_point:
+        mac = ec.register_resource("ns3::ApWifiMac")
+    else:
+        mac = ec.register_resource("ns3::StaWifiMac")
+
+    ec.set(mac, "Standard", "WIFI_PHY_STANDARD_80211a")
+    ec.register_connection(dev, mac)
+
+    return dev, phy
+
+def add_random_mobility(ec, node, x, y, z, speed, bounds_width, 
+        bounds_height):
+    position = "%d:%d:%d" % (x, y, z)
+    bounds = "0|%d|0|%d" % (bounds_width, bounds_height) 
+    speed = "ns3::UniformRandomVariable[Min=%d|Max=%s]" % (speed, speed)
+    pause = "ns3::ConstantRandomVariable[Constant=1.0]"
+    
+    mobility = ec.register_resource("ns3::RandomDirection2dMobilityModel")
+    ec.set(mobility, "Position", position)
+    ec.set(mobility, "Bounds", bounds)
+    ec.set(mobility, "Speed", speed)
+    ec.set(mobility, "Pause",  pause)
+    ec.register_connection(node, mobility)
+    return mobility
+
+def add_constant_mobility(ec, node, x, y, z):
+    mobility = ec.register_resource("ns3::ConstantPositionMobilityModel") 
+    position = "%d:%d:%d" % (x, y, z)
+    ec.set(mobility, "Position", position)
+    ec.register_connection(node, mobility)
+    return mobility
+
+def add_wifi_channel(ec):
+    channel = ec.register_resource("ns3::YansWifiChannel")
+    delay = ec.register_resource("ns3::ConstantSpeedPropagationDelayModel")
+    ec.register_connection(channel, delay)
+
+    loss  = ec.register_resource("ns3::LogDistancePropagationLossModel")
+    ec.register_connection(channel, loss)
+
+    return channel
+
+class LinuxNS3DceApplicationTest(unittest.TestCase):
+    def setUp(self):
+        #self.fedora_host = "nepi2.pl.sophia.inria.fr"
+        self.fedora_host = "planetlabpc1.upf.edu"
+        self.fedora_user = "inria_nepi"
+        self.fedora_identity = "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])
+
+    def test_dce_ping(self):
+        ec = ExperimentController(exp_id = "test-dce-ping")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.set(simu, "enableDCE", True)
+        ec.set(simu, "buildMode", "debug")
+        ec.set(simu, "nsLog", "DceApplication")
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        ec.set(nsnode1, "enableDCE", True)
+        p2p1 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+        ec.set(p2p1, "DataRate", "5Mbps")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        ec.set(nsnode2, "enableDCE", True)
+        p2p2 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+        ec.set(p2p2, "DataRate", "5Mbps")
+
+        # Create channel
+        chan = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(chan, "Delay", "2ms")
+
+        ec.register_connection(chan, p2p1)
+        ec.register_connection(chan, p2p2)
+
+        ### create applications
+        ping = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set (ping, "sources", "http://www.skbuff.net/iputils/iputils-s20101006.tar.bz2")
+        ec.set (ping, "build", "tar xvjf ${SRC}/iputils-s20101006.tar.bz2 && "
+                "cd iputils-s20101006/ && "
+                "sed -i 's/CFLAGS=/CFLAGS+=/g' Makefile && "
+                "make CFLAGS=-fPIC LDFLAGS=-pie ping && "
+                "cp ping ${BIN_DCE} ")
+        ec.set (ping, "binary", "ping")
+        ec.set (ping, "stackSize", 1<<20)
+        ec.set (ping, "arguments", "-c 10;-s 1000;10.0.0.2")
+        ec.set (ping, "StartTime", "1s")
+        ec.set (ping, "StopTime", "20s")
+        ec.register_connection(ping, nsnode1)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+
+        expected = "ping -c 10 -s 1000 10.0.0.2"
+        cmdline = ec.trace(ping, "cmdline")
+        self.assertTrue(cmdline.find(expected) > -1, cmdline)
+        
+        expected = "Start Time: NS3 Time:          1s ("
+        status = ec.trace(ping, "status")
+        self.assertTrue(status.find(expected) > -1, status)
+
+        expected = "10 packets transmitted, 10 received, 0% packet loss, time 9002ms"
+        stdout = ec.trace(ping, "stdout")
+        self.assertTrue(stdout.find(expected) > -1, stdout)
+
+        stderr = ec.trace(simu, "stderr")
+        expected = "DceApplication:StartApplication"
+        self.assertTrue(stderr.find(expected) > -1, stderr)
+
+        ec.shutdown()
+
+    def test_dce_ccn(self):
+        ec = ExperimentController(exp_id = "test-dce-ccn")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.set(simu, "enableDCE", True)
+        ec.set(simu, "buildMode", "debug")
+        ec.set(simu, "nsLog", "DceApplication")
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        ec.set(nsnode1, "enableDCE", True)
+        p2p1 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+        ec.set(p2p1, "DataRate", "5Mbps")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        ec.set(nsnode2, "enableDCE", True)
+        p2p2 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+        ec.set(p2p2, "DataRate", "5Mbps")
+
+        # Create channel
+        chan = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(chan, "Delay", "2ms")
+
+        ec.register_connection(chan, p2p1)
+        ec.register_connection(chan, p2p2)
+
+        ### create applications
+        ccnd1 = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set(ccnd1, "depends", "libpcap0.8-dev openjdk-6-jdk ant1.8 autoconf "
+            "libssl-dev libexpat-dev libpcap-dev libecryptfs0 libxml2-utils auto"
+            "make gawk gcc g++ git-core pkg-config libpcre3-dev openjdk-6-jre-lib")
+        ec.set (ccnd1, "sources", "http://www.ccnx.org/releases/ccnx-0.7.2.tar.gz")
+        ec.set (ccnd1, "build", "tar xvjf ${SRC}/iputils-s20101006.tar.bz2 && "
+                "tar zxf ${SRC}/ccnx-0.7.2.tar.gz && "
+                "cd ccnx-0.7.2 && "
+                " INSTALL_BASE=${BIN_DCE} ./configure && "
+                " make MORE_LDLIBS=-pie && "
+                " make install ")
+        ec.set (ccnd1, "binary", "ccndstart")
+        ec.set (ccnd1, "stackSize", 1<<20)
+        ec.set (ccnd1, "StartTime", "1s")
+        ec.set (ccnd1, "StopTime", "20s")
+        ec.register_connection(ccnd1, nsnode1)
+
+        ccnkill1 = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set (ccnkill1, "binary", "ccnsmoketest")
+        ec.set (ccnkill1, "arguments", "kill")
+        ec.set (ccnkill1, "stdinFile", "")
+        ec.set (ccnkill1, "stackSize", 1<<20)
+        ec.set (ccnkill1, "StartTime", "110s")
+        ec.set (ccnkill1, "StopTime", "120s")
+        ec.register_connection(ccnkill1, nsnode1)
+
+        repofile = os.path.join(
+            os.path.dirname(os.path.realpath(__file__)),
+            "repoFile1")
+
+        ccnr = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set (ccnr, "binary", "ccnr")
+        ec.set (ccnr, "environment", "CCNR_DIRECTORY=/REPO/")
+        ec.set (ccnr, "files", "%s=/REPO/repoFile1" % repofile) 
+        ec.set (ccnr, "stackSize", 1<<20)
+        ec.set (ccnr, "StartTime", "2s")
+        ec.set (ccnr, "StopTime", "120s")
+        ec.register_connection(ccnr, nsnode1)
+
+        ccndc1 = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set (ccndc1, "binary", "ccndc")
+        ec.set (ccndc1, "arguments", "-v;add;ccnx:/;udp;10.0.0.2")
+        ec.set (ccndc1, "stackSize", 1<<20)
+        ec.set (ccndc1, "StartTime", "2s")
+        ec.set (ccndc1, "StopTime", "120s")
+        ec.register_connection(ccndc1, nsnode1)
+
+        ccnd2 = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set (ccnd2, "binary", "ccndstart")
+        ec.set (ccnd2, "stackSize", 1<<20)
+        ec.set (ccnd2, "StartTime", "1s")
+        ec.set (ccnd2, "StopTime", "120s")
+        ec.register_connection(ccnd2, nsnode2)
+
+        ccndc2 = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set (ccndc2, "binary", "ccndc")
+        ec.set (ccndc2, "arguments", "-v;add;ccnx:/;udp;10.0.0.1")
+        ec.set (ccndc2, "stackSize", 1<<20)
+        ec.set (ccndc2, "StartTime", "2s")
+        ec.set (ccndc2, "StopTime", "120s")
+        ec.register_connection(ccndc2, nsnode2)
+
+        ccnpeek = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set (ccnpeek, "binary", "ccnpeek")
+        ec.set (ccnpeek, "arguments", "ccnx:/test/bunny.ts")
+        ec.set (ccnpeek, "stdinFile", "")
+        ec.set (ccnpeek, "stackSize", 1<<20)
+        ec.set (ccnpeek, "StartTime", "4s")
+        ec.set (ccnpeek, "StopTime", "120s")
+        ec.register_connection(ccnpeek, nsnode2)
+
+        ccncat = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set (ccncat, "binary", "ccncat")
+        ec.set (ccncat, "arguments", "ccnx:/test/bunny.ts")
+        ec.set (ccncat, "stdinFile", "")
+        ec.set (ccncat, "stackSize", 1<<20)
+        ec.set (ccncat, "StartTime", "4s")
+        ec.set (ccncat, "StopTime", "120s")
+        ec.register_connection(ccncat, nsnode2)
+
+        ccnkill2 = ec.register_resource("ns3::LinuxDceApplication")
+        ec.set (ccnkill2, "binary", "ccnsmoketest")
+        ec.set (ccnkill2, "arguments", "kill")
+        ec.set (ccnkill2, "stdinFile", "")
+        ec.set (ccnkill2, "stackSize", 1<<20)
+        ec.set (ccnkill2, "StartTime", "110s")
+        ec.set (ccnkill2, "StopTime", "120s")
+        ec.register_connection(ccnkill2, nsnode2)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+
+        print ec.trace(ccncat, "cmdline")
+        """
+        expected = "ping -c 10 -s 1000 10.0.0.2"
+        cmdline = ec.trace(ping, "cmdline")
+        self.assertTrue(cmdline.find(expected) > -1, cmdline)
+        """
+
+        print ec.trace(cccat, "status")
+        """
+        expected = "Start Time: NS3 Time:          1s ("
+        status = ec.trace(ping, "status")
+        self.assertTrue(status.find(expected) > -1, status)
+        """
+
+        print len(ec.trace(ccncat, "stdout"))
+        """
+        expected = "10 packets transmitted, 10 received, 0% packet loss, time 9002ms"
+        stdout = ec.trace(ping, "stdout")
+        self.assertTrue(stdout.find(expected) > -1, stdout)
+        """
+
+        stderr = ec.trace(simu, "stderr")
+        expected = "DceApplication:StartApplication"
+        self.assertTrue(stderr.find(expected) > -1, stderr)
+
+        ec.shutdown()
+
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/test/resources/linux/ns3/ns3simulation.py b/test/resources/linux/ns3/ns3simulation.py
new file mode 100644 (file)
index 0000000..8114685
--- /dev/null
@@ -0,0 +1,831 @@
+#!/usr/bin/env python
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.ec import ExperimentController 
+from nepi.execution.trace import TraceAttr
+
+import os
+import time
+import unittest
+
+def add_ns3_node(ec, simu):
+    node = ec.register_resource("ns3::Node")
+    ec.register_connection(node, simu)
+
+    ipv4 = ec.register_resource("ns3::Ipv4L3Protocol")
+    ec.register_connection(node, ipv4)
+
+    arp = ec.register_resource("ns3::ArpL3Protocol")
+    ec.register_connection(node, arp)
+    
+    icmp = ec.register_resource("ns3::Icmpv4L4Protocol")
+    ec.register_connection(node, icmp)
+
+    udp = ec.register_resource("ns3::UdpL4Protocol")
+    ec.register_connection(node, udp)
+
+    return node
+
+def add_point2point_device(ec, node, address = None,  prefix = None):
+    dev = ec.register_resource("ns3::PointToPointNetDevice")
+    if address:
+       ec.set(dev, "ip", address)
+    if prefix:
+       ec.set(dev, "prefix", prefix)
+    ec.register_connection(node, dev)
+
+    queue = ec.register_resource("ns3::DropTailQueue")
+    ec.register_connection(dev, queue)
+
+    return dev
+
+def add_csma_device(ec, node, address = None, prefix = None):
+    dev = ec.register_resource("ns3::CsmaNetDevice")
+    if address:
+        ec.set(dev, "ip", address)
+    if prefix:
+        ec.set(dev, "prefix", prefix)
+    ec.register_connection(node, dev)
+
+    queue = ec.register_resource("ns3::DropTailQueue")
+    ec.register_connection(dev, queue)
+
+    return dev
+
+def add_wifi_device(ec, node, address = None, prefix = None, 
+        access_point = False):
+    dev = ec.register_resource("ns3::WifiNetDevice")
+    if address:
+        ec.set(dev, "ip", address)
+    if prefix:
+        ec.set(dev, "prefix", prefix)
+    ec.register_connection(node, dev)
+
+    phy = ec.register_resource("ns3::YansWifiPhy")
+    ec.set(phy, "Standard", "WIFI_PHY_STANDARD_80211a")
+    ec.register_connection(dev, phy)
+
+    error = ec.register_resource("ns3::NistErrorRateModel")
+    ec.register_connection(phy, error)
+
+    manager = ec.register_resource("ns3::ArfWifiManager")
+    ec.register_connection(dev, manager)
+
+    if access_point:
+        mac = ec.register_resource("ns3::ApWifiMac")
+    else:
+        mac = ec.register_resource("ns3::StaWifiMac")
+
+    ec.set(mac, "Standard", "WIFI_PHY_STANDARD_80211a")
+    ec.register_connection(dev, mac)
+
+    return dev, phy
+
+def add_random_mobility(ec, node, x, y, z, speed, bounds_width, 
+        bounds_height):
+    position = "%d:%d:%d" % (x, y, z)
+    bounds = "0|%d|0|%d" % (bounds_width, bounds_height) 
+    speed = "ns3::UniformRandomVariable[Min=%d|Max=%s]" % (speed, speed)
+    pause = "ns3::ConstantRandomVariable[Constant=1.0]"
+    
+    mobility = ec.register_resource("ns3::RandomDirection2dMobilityModel")
+    ec.set(mobility, "Position", position)
+    ec.set(mobility, "Bounds", bounds)
+    ec.set(mobility, "Speed", speed)
+    ec.set(mobility, "Pause",  pause)
+    ec.register_connection(node, mobility)
+    return mobility
+
+def add_constant_mobility(ec, node, x, y, z):
+    mobility = ec.register_resource("ns3::ConstantPositionMobilityModel") 
+    position = "%d:%d:%d" % (x, y, z)
+    ec.set(mobility, "Position", position)
+    ec.register_connection(node, mobility)
+    return mobility
+
+def add_wifi_channel(ec):
+    channel = ec.register_resource("ns3::YansWifiChannel")
+    delay = ec.register_resource("ns3::ConstantSpeedPropagationDelayModel")
+    ec.register_connection(channel, delay)
+
+    loss  = ec.register_resource("ns3::LogDistancePropagationLossModel")
+    ec.register_connection(channel, loss)
+
+    return channel
+
+class LinuxNS3SimulationTest(unittest.TestCase):
+    def setUp(self):
+        self.fedora_host = "nepi2.pl.sophia.inria.fr"
+        self.fedora_user = "inria_nepi"
+        self.fedora_identity = "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])
+
+    def test_local_p2p_ping(self):
+        ec = ExperimentController(exp_id = "test-ns3-local-p2p")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", "localhost")
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        dev1 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        dev2 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+
+        # Create channel
+        chan = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(chan, "Delay", "0s")
+        ec.register_connection(chan, dev1)
+        ec.register_connection(chan, dev2)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.0.2")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "0s")
+        ec.set (ping, "StopTime", "20s")
+        ec.register_connection(ping, nsnode1)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+        
+        stdout = ec.trace(simu, "stdout") 
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
+
+        ec.shutdown()
+
+    def test_simple_p2p_ping(self):
+        ec = ExperimentController(exp_id = "test-ns3-p2p-ping")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        dev1 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        dev2 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+
+        # Create channel
+        chan = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(chan, "Delay", "0s")
+        ec.register_connection(chan, dev1)
+        ec.register_connection(chan, dev2)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.0.2")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "0s")
+        ec.set (ping, "StopTime", "20s")
+        ec.register_connection(ping, nsnode1)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+        
+        stdout = ec.trace(simu, "stdout") 
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
+
+        ec.shutdown()
+
+    def test_simple_cmsa_ping(self):
+        ec = ExperimentController(exp_id = "test-ns3-csma-ping")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        dev1 = add_csma_device(ec, nsnode1, "10.0.0.1", "30")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        dev2 = add_csma_device(ec, nsnode2, "10.0.0.2", "30")
+
+        # Create channel
+        chan = ec.register_resource("ns3::CsmaChannel")
+        ec.set(chan, "Delay", "0s")
+        ec.register_connection(chan, dev1)
+        ec.register_connection(chan, dev2)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.0.2")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "0s")
+        ec.set (ping, "StopTime", "20s")
+        ec.register_connection(ping, nsnode1)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+        
+        stdout = ec.trace(simu, "stdout") 
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
+
+        ec.shutdown()
+
+    def test_compile_local_source(self):
+        ec = ExperimentController(exp_id = "test-ns3-local-source")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        sources = os.path.join(os.path.dirname(os.path.realpath(__file__)), 
+                "ns-3.18-user.tar.gz")
+        ec.set(simu, "sources", sources)
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        dev1 = add_csma_device(ec, nsnode1, "10.0.0.1", "30")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        dev2 = add_csma_device(ec, nsnode2, "10.0.0.2", "30")
+
+        # Create channel
+        chan = ec.register_resource("ns3::CsmaChannel")
+        ec.set(chan, "Delay", "0s")
+        ec.register_connection(chan, dev1)
+        ec.register_connection(chan, dev2)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.0.2")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "0s")
+        ec.set (ping, "StopTime", "20s")
+        ec.register_connection(ping, nsnode1)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+        
+        stdout = ec.trace(simu, "stdout") 
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
+        
+        ec.shutdown()
+
+    def test_compile_debug_mode(self):
+        ec = ExperimentController(exp_id = "test-ns3-debug-mode")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.set(simu, "nsLog", "V4Ping:Node")
+        ec.set(simu, "buildMode", "debug")
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        dev1 = add_csma_device(ec, nsnode1, "10.0.0.1", "30")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        dev2 = add_csma_device(ec, nsnode2, "10.0.0.2", "30")
+
+        # Create channel
+        chan = ec.register_resource("ns3::CsmaChannel")
+        ec.set(chan, "Delay", "0s")
+        ec.register_connection(chan, dev1)
+        ec.register_connection(chan, dev2)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.0.2")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "0s")
+        ec.set (ping, "StopTime", "20s")
+        ec.register_connection(ping, nsnode1)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+        
+        stdout = ec.trace(simu, "stdout") 
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
+        
+        stderr = ec.trace(simu, "stderr")
+        expected = "V4Ping:Read32"
+        self.assertTrue(stderr.find(expected) > -1)
+
+        ec.shutdown()
+
+    def test_real_time(self):
+        ec = ExperimentController(exp_id = "test-ns3-real-time")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "simulatorImplementationType", "ns3::RealtimeSimulatorImpl")
+        ec.set(simu, "checksumEnabled", True)
+        ec.set(simu, "verbose", True)
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        dev1 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        dev2 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+
+        # Create channel
+        chan = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(chan, "Delay", "0s")
+        ec.register_connection(chan, dev1)
+        ec.register_connection(chan, dev2)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.0.2")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "0s")
+        ec.set (ping, "StopTime", "20s")
+        ec.register_connection(ping, nsnode1)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+      
+        stdout = ec.trace(simu, "stdout") 
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
+
+        rm = ec.get_resource(ping)
+        start_time = rm.start_time
+        stop_time = rm.stop_time
+        delta = stop_time - start_time
+
+        self.assertTrue(delta.seconds >= 20, "Time elapsed %d" % delta.seconds)
+        self.assertTrue(delta.seconds < 25, "Time elapsed %d" % delta.seconds)
+
+        ec.shutdown()
+
+    def test_traces(self):
+        ec = ExperimentController(exp_id = "test-ns3-traces")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        dev1 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        dev2 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+
+        # Create channel
+        chan = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(chan, "Delay", "0s")
+        ec.register_connection(chan, dev1)
+        ec.register_connection(chan, dev2)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.0.2")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "0s")
+        ec.set (ping, "StopTime", "20s")
+        ec.register_connection(ping, nsnode1)
+
+        # enable traces
+        ec.enable_trace(dev1, "pcap")
+        ec.enable_trace(dev1, "promiscPcap")
+        ec.enable_trace(dev1, "ascii")
+
+        ec.enable_trace(dev2, "pcap")
+        ec.enable_trace(dev2, "promiscPcap")
+        ec.enable_trace(dev2, "ascii")
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+
+        # Trace verification
+        rm_simu = ec.get_resource(simu)
+
+        # TODO: Fix this in ns-3: pcap traces do not flush until the Simulator 
+        #   process is ended, so we can't get the traces of the 'pcap' and
+        #   'promiscPcap' traces.
+        #
+        #for trace in ["pcap", "promiscPcap", "ascii"]:
+        for trace in ["ascii"]:
+            for guid in [dev1, dev2]:
+                output = ec.trace(guid, trace)
+
+                size = ec.trace(guid, trace, attr = TraceAttr.SIZE)
+                self.assertEquals(size, len(output))
+                self.assertTrue(size > 100)
+                
+                block = ec.trace(guid, trace, attr = TraceAttr.STREAM, block = 5, offset = 1)
+                self.assertEquals(block, output[5:10])
+
+                trace_path = ec.trace(guid, trace, attr = TraceAttr.PATH)
+                rm = ec.get_resource(guid)
+                path = os.path.join(rm_simu.run_home, rm._trace_filename.get(trace))
+                self.assertEquals(trace_path, path)
+
+        ec.shutdown()
+
+    def test_simple_wifi_ping(self):
+        bounds_width = bounds_height = 200
+        x = y = 100
+        speed = 1
+
+        ec = ExperimentController(exp_id = "test-ns3-wifi-ping")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        dev1, phy1 = add_wifi_device(ec, nsnode1, "10.0.0.1", "24", access_point = True)
+        mobility1 = add_constant_mobility(ec, nsnode1, x, y, 0)
+
+        nsnode2 = add_ns3_node(ec, simu)
+        dev2, phy2 = add_wifi_device(ec, nsnode2, "10.0.0.2", "24", access_point = False)
+        mobility1 = add_constant_mobility(ec, nsnode2, x, y, 0)
+        #mobility2 = add_random_mobility(ec, nsnode2, x, y, 0, speed, bounds_width, bounds_height)
+
+        # Create channel
+        chan = add_wifi_channel(ec)
+        ec.register_connection(chan, phy1)
+        ec.register_connection(chan, phy2)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.0.1")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "1s")
+        ec.set (ping, "StopTime", "21s")
+        ec.register_connection(ping, nsnode2)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+        
+        stdout = ec.trace(simu, "stdout")
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
+
+        ec.shutdown()
+
+    def test_routing(self):
+        """ 
+        network topology:
+                                n4
+                                |
+           n1 -- p2p -- n2 -- csma -- n5 -- p2p -- n6
+           |                    | 
+           ping n6              n3
+           
+
+        """
+        ec = ExperimentController(exp_id = "test-ns3-routes")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        p2p12 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        p2p21 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+        csma2 = add_csma_device(ec, nsnode2, "10.0.1.1", "24")
+
+        nsnode3 = add_ns3_node(ec, simu)
+        csma3 = add_csma_device(ec, nsnode3, "10.0.1.2", "24")
+
+        nsnode4 = add_ns3_node(ec, simu)
+        csma4 = add_csma_device(ec, nsnode4, "10.0.1.3", "24")
+
+        nsnode5 = add_ns3_node(ec, simu)
+        p2p56 = add_point2point_device(ec, nsnode5, "10.0.2.1", "30")
+        csma5 = add_csma_device(ec, nsnode5, "10.0.1.4", "24")
+
+        nsnode6 = add_ns3_node(ec, simu)
+        p2p65 = add_point2point_device(ec, nsnode6, "10.0.2.2", "30")
+
+        # P2P chan1
+        p2p_chan1 = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(p2p_chan1, "Delay", "0s")
+        ec.register_connection(p2p_chan1, p2p12)
+        ec.register_connection(p2p_chan1, p2p21)
+
+        # CSMA chan
+        csma_chan = ec.register_resource("ns3::CsmaChannel")
+        ec.set(csma_chan, "Delay", "0s")
+        ec.register_connection(csma_chan, csma2)
+        ec.register_connection(csma_chan, csma3)
+        ec.register_connection(csma_chan, csma4)
+        ec.register_connection(csma_chan, csma5)
+
+        # P2P chan2
+        p2p_chan2 = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(p2p_chan2, "Delay", "0s")
+        ec.register_connection(p2p_chan2, p2p56)
+        ec.register_connection(p2p_chan2, p2p65)
+
+        # Add routes - n1 - n6
+        r1 = ec.register_resource("ns3::Route")
+        ec.set(r1, "network", "10.0.2.0")
+        ec.set(r1, "prefix", "30")
+        ec.set(r1, "nexthop", "10.0.0.2")
+        ec.register_connection(r1, nsnode1)
+
+        # Add routes - n2 - n6
+        r2 = ec.register_resource("ns3::Route")
+        ec.set(r2, "network", "10.0.2.0")
+        ec.set(r2, "prefix", "30")
+        ec.set(r2, "nexthop", "10.0.1.4")
+        ec.register_connection(r2, nsnode2)
+
+        # Add routes - n5 - n1
+        r5 = ec.register_resource("ns3::Route")
+        ec.set(r5, "network", "10.0.0.0")
+        ec.set(r5, "prefix", "30")
+        ec.set(r5, "nexthop", "10.0.1.1")
+        ec.register_connection(r5, nsnode5)
+
+        # Add routes - n6 - n1
+        r6 = ec.register_resource("ns3::Route")
+        ec.set(r6, "network", "10.0.0.0")
+        ec.set(r6, "prefix", "30")
+        ec.set(r6, "nexthop", "10.0.2.1")
+        ec.register_connection(r6, nsnode6)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.2.2")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "1s")
+        ec.set (ping, "StopTime", "21s")
+        ec.register_connection(ping, nsnode1)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+        
+        stdout = ec.trace(simu, "stdout")
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
+
+        ec.shutdown()
+
+    def ztest_automatic_routing(self):
+        """ 
+        network topology:
+                                n4
+                                |
+           n1 -- p2p -- n2 -- csma -- n5 -- p2p -- n6
+           |                    | 
+           ping n6              n3
+           
+
+        """
+        ec = ExperimentController(exp_id = "test-ns3-routing")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.set(simu, "populateRoutingTables", True)
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        p2p12 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        p2p21 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+        csma2 = add_csma_device(ec, nsnode2, "10.0.1.1", "24")
+
+        nsnode3 = add_ns3_node(ec, simu)
+        csma3 = add_csma_device(ec, nsnode3, "10.0.1.2", "24")
+
+        nsnode4 = add_ns3_node(ec, simu)
+        csma4 = add_csma_device(ec, nsnode4, "10.0.1.3", "24")
+
+        nsnode5 = add_ns3_node(ec, simu)
+        p2p56 = add_point2point_device(ec, nsnode5, "10.0.2.1", "30")
+        csma5 = add_csma_device(ec, nsnode5, "10.0.1.4", "24")
+
+        nsnode6 = add_ns3_node(ec, simu)
+        p2p65 = add_point2point_device(ec, nsnode6, "10.0.2.2", "30")
+
+        # P2P chan1
+        p2p_chan1 = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(p2p_chan1, "Delay", "0s")
+        ec.register_connection(p2p_chan1, p2p12)
+        ec.register_connection(p2p_chan1, p2p21)
+
+        # CSMA chan
+        csma_chan = ec.register_resource("ns3::CsmaChannel")
+        ec.set(csma_chan, "Delay", "0s")
+        ec.register_connection(csma_chan, csma2)
+        ec.register_connection(csma_chan, csma3)
+        ec.register_connection(csma_chan, csma4)
+        ec.register_connection(csma_chan, csma5)
+
+        # P2P chan2
+        p2p_chan2 = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(p2p_chan2, "Delay", "0s")
+        ec.register_connection(p2p_chan2, p2p56)
+        ec.register_connection(p2p_chan2, p2p65)
+
+        ### create pinger
+        ping = ec.register_resource("ns3::V4Ping")
+        ec.set (ping, "Remote", "10.0.1.2")
+        ec.set (ping, "Interval", "1s")
+        ec.set (ping, "Verbose", True)
+        ec.set (ping, "StartTime", "1s")
+        ec.set (ping, "StopTime", "21s")
+        ec.register_connection(ping, nsnode1)
+
+        ec.deploy()
+
+        ec.wait_finished([ping])
+        
+        stdout = ec.trace(simu, "stdout")
+
+        print stdout
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
+
+        ec.shutdown()
+
+    def test_dce(self):
+        ec = ExperimentController(exp_id = "test-ns3-dce")
+        
+        node = ec.register_resource("LinuxNode")
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
+        ec.set(node, "identity", self.fedora_identity)
+        ec.set(node, "cleanProcesses", True)
+        #ec.set(node, "cleanHome", True)
+
+        simu = ec.register_resource("LinuxNS3Simulation")
+        ec.set(simu, "verbose", True)
+        ec.set(simu, "enableDCE", True)
+        ec.set(simu, "buildMode", "debug")
+        ec.set(simu, "nsLog", "DceApplication")
+        ec.register_connection(simu, node)
+
+        nsnode1 = add_ns3_node(ec, simu)
+        ec.set(nsnode1, "enableDCE", True)
+        p2p1 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+        ec.set(p2p1, "DataRate", "5Mbps")
+
+        nsnode2 = add_ns3_node(ec, simu)
+        ec.set(nsnode2, "enableDCE", True)
+        p2p2 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+        ec.set(p2p2, "DataRate", "5Mbps")
+
+        # Create channel
+        chan = ec.register_resource("ns3::PointToPointChannel")
+        ec.set(chan, "Delay", "2ms")
+
+        ec.register_connection(chan, p2p1)
+        ec.register_connection(chan, p2p2)
+
+        ### create applications
+        udp_perf = ec.register_resource("ns3::DceApplication")
+        ec.set (udp_perf, "binary", "udp-perf")
+        ec.set (udp_perf, "stackSize", 1<<20)
+        ec.set (udp_perf, "arguments", "--duration=10;--nodes=2")
+        ec.set (udp_perf, "StartTime", "1s")
+        ec.set (udp_perf, "StopTime", "20s")
+        ec.register_connection(udp_perf, nsnode1)
+
+        udp_perf_client = ec.register_resource("ns3::DceApplication")
+        ec.set (udp_perf_client, "binary", "udp-perf")
+        ec.set (udp_perf_client, "stackSize", 1<<20)
+        ec.set (udp_perf_client, "arguments", "--client;--nodes=2;--host=10.0.0.1;--duration=10")
+        ec.set (udp_perf_client, "StartTime", "2s")
+        ec.set (udp_perf_client, "StopTime", "20s")
+        ec.register_connection(udp_perf_client, nsnode2)
+
+        ec.deploy()
+
+        ec.wait_finished([udp_perf_client])
+
+        expected = "udp-perf --duration=10 --nodes=2"
+        cmdline = ec.trace(udp_perf, "cmdline")
+        self.assertTrue(cmdline.find(expected) > -1, cmdline)
+
+        expected = "Start Time: NS3 Time:          1s ("
+        status = ec.trace(udp_perf, "status")
+        self.assertTrue(status.find(expected) > -1, status)
+
+        expected = "received=1500 bytes, 1 reads (@1500 bytes) 1500"
+        stdout = ec.trace(udp_perf, "stdout")
+        self.assertTrue(stdout.find(expected) > -1, stdout)
+
+        stderr = ec.trace(simu, "stderr")
+        expected = "DceApplication:StartApplication"
+        self.assertTrue(stderr.find(expected) > -1, stderr)
+
+        ec.shutdown()
+
+
+if __name__ == '__main__':
+    unittest.main()
+
diff --git a/test/resources/linux/ns3/repoFile1 b/test/resources/linux/ns3/repoFile1
new file mode 100644 (file)
index 0000000..0899dbd
Binary files /dev/null and b/test/resources/linux/ns3/repoFile1 differ
index 8846690..6530276 100755 (executable)
@@ -29,7 +29,7 @@ import unittest
 class LinuxPingTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
         self.ubuntu_user = "alina"
index 6c9a9be..6ba7375 100755 (executable)
@@ -29,7 +29,7 @@ import unittest
 class LinuxTcpdumpTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
         self.ubuntu_user = "alina"
index dfdae42..996472e 100755 (executable)
@@ -29,7 +29,7 @@ import unittest
 class LinuxTracerouteTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
         self.ubuntu_user = "alina"
index aeafe6a..37bfc88 100755 (executable)
@@ -29,7 +29,7 @@ import unittest
 class LinuxUdpTestTestCase(unittest.TestCase):
     def setUp(self):
         self.fedora_host = "nepi2.pl.sophia.inria.fr"
-        self.fedora_user = "inria_test"
+        self.fedora_user = "inria_nepi"
 
         self.ubuntu_host = "roseval.pl.sophia.inria.fr"
         self.ubuntu_user = "alina"
index d3b11d1..8765761 100755 (executable)
 
 from nepi.resources.ns3.ns3wrapper import NS3Wrapper
 
-import os.path
+import StringIO
+import subprocess
+import sys
 import time
-import tempfile
 import unittest
 
 class NS3WrapperTest(unittest.TestCase):
@@ -92,11 +93,10 @@ class NS3WrapperTest(unittest.TestCase):
         addresses = wrapper.invoke(ip, "Assign", devs)
 
         ### Create source
-        config = wrapper.singleton("Config")
-        
         # Config::SetDefault ("ns3::Ipv4RawSocketImpl::Protocol", StringValue ("2"));
         proto = wrapper.create("StringValue", "2")
-        wrapper.invoke(config, "SetDefault", "ns3::Ipv4RawSocketImpl::Protocol", proto)
+        wrapper.invoke("singleton::Config", "SetDefault", 
+                "ns3::Ipv4RawSocketImpl::Protocol", proto)
 
         # InetSocketAddress dst = InetSocketAddress (addresses.GetAddress (3));
         addr3 = wrapper.invoke(addresses, "GetAddress", 3)
@@ -105,16 +105,6 @@ class NS3WrapperTest(unittest.TestCase):
         # OnOffHelper onoff = OnOffHelper ("ns3::Ipv4RawSocketFactory", dst);
         onoff = wrapper.create("OnOffHelper", "ns3::Ipv4RawSocketFactory", dst)
 
-        # onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1.0)));
-        cv1 = wrapper.create("ConstantVariable", 1.0)
-        rand1 = wrapper.create("RandomVariableValue", cv1)
-        wrapper.invoke(onoff, "SetAttribute", "OnTime", rand1)
-
-        # onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0.0)));
-        cv2 = wrapper.create("ConstantVariable", 0.0)
-        rand2 = wrapper.create("RandomVariableValue", cv2)
-        wrapper.invoke(onoff, "SetAttribute", "OffTime", rand2)
-
         # onoff.SetAttribute ("DataRate", DataRateValue (DataRate (15000)));
         dr2 = wrapper.create("DataRate", 15000)
         drv2 = wrapper.create("DataRateValue", dr2)
@@ -183,41 +173,256 @@ class NS3WrapperTest(unittest.TestCase):
         s6 = wrapper.create ("Seconds", 5.0)
         wrapper.invoke (apps, "Stop", s6)
 
+        ### configure tracing
+        #csma.EnablePcapAll ("csma-ping", false);
+        wrapper.invoke(csma, "EnablePcapAll", "/tmp/csma-ping-pcap", False)
+        #csma.EnableAsciiAll ("csma-ping", false);
+        wrapper.invoke(csma, "EnableAsciiAll", "/tmp/csma-ping-ascii")
         def SinkRx(packet, address):
             print packet
 
         def PingRtt(context, rtt):
             print context, rtt
-
-        ### configure tracing
-        #csma.EnablePcapAll ("csma-ping", false);
-        wrapper.invoke(csma, "EnablePcapAll", "csma-ping", False)
-       
-        # No binging for callback
+      
+        # XXX: No biding for MakeCallback
         #Config::ConnectWithoutContext ("/NodeList/3/ApplicationList/0/$ns3::PacketSink/Rx", 
         # MakeCallback (&SinkRx));
         #cb = wrapper.create("MakeCallback", SinkRx)
-        #wrapper.invoke(config, "ConnectWithoutContext", 
+        #wrapper.invoke("singleton::Config", "ConnectWithoutContext", 
         #        "/NodeList/3/ApplicationList/0/$ns3::PacketSink/Rx", cb)
 
         # Config::Connect ("/NodeList/*/ApplicationList/*/$ns3::V4Ping/Rtt", 
         # MakeCallback (&PingRtt));
         #cb2 = wrapper.create("MakeCallback", PingRtt)
-        #wrapper.invoke(config, "ConnectWithoutContext", 
+        #wrapper.invoke("singleton::Config", "ConnectWithoutContext", 
         #        "/NodeList/*/ApplicationList/*/$ns3::V4Ping/Rtt", 
         #        cb2)
 
         # Packet::EnablePrinting ();
-        packet = wrapper.singleton("Packet")
-        wrapper.invoke(packet, "EnablePrinting")
+        wrapper.invoke("singleton::Packet", "EnablePrinting")
 
         ### run Simulation
         # Simulator::Run ();
-        simulator = wrapper.singleton("Simulator")
-        wrapper.invoke(simulator, "Run")
+        wrapper.invoke("singleton::Simulator", "Run")
 
         # Simulator::Destroy ();
-        wrapper.invoke(simulator, "Destroy")
+        wrapper.invoke("singleton::Simulator", "Destroy")
+
+        p = subprocess.Popen("ls /tmp/csma-ping-* | wc -w", stdout = subprocess.PIPE, 
+                stderr = subprocess.PIPE, shell = True)
+        (out, err) = p.communicate()
+
+        self.assertEquals(int(out), 8)
+
+        p = subprocess.Popen("rm /tmp/csma-ping-*",  shell = True)
+        p.communicate()
+
+    def test_start(self):
+        # Instantiate ns-3
+        wrapper = NS3Wrapper()
+
+        ### create 2  nodes
+        c = wrapper.create("NodeContainer")
+
+        # c.Create (2);
+        wrapper.invoke(c, "Create", 2)
+
+        ### connect the nodes to a shared channel
+        # CsmaHelper csma;
+        csma = wrapper.create("CsmaHelper")
+
+        # csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate (5000000)));
+        dr = wrapper.create("DataRate", 5000000)
+        drv = wrapper.create("DataRateValue", dr)
+        wrapper.invoke(csma, "SetChannelAttribute", "DataRate", drv)
+
+        # csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
+        ms = wrapper.create("MilliSeconds", 2)
+        delay = wrapper.create("TimeValue", ms)
+        wrapper.invoke(csma, "SetChannelAttribute", "Delay", delay)
+
+        # NetDeviceContainer devs = csma.Install (c);
+        devs = wrapper.invoke(csma, "Install", c)
+
+        ### add IP stack to all nodes
+        # InternetStackHelper ipStack;
+        ipStack = wrapper.create("InternetStackHelper")
+        
+        # ipStack.Install (c);
+        wrapper.invoke(ipStack, "Install", c)
+
+        ### assign ip addresses
+        #Ipv4AddressHelper ip;
+        ip = wrapper.create("Ipv4AddressHelper")
+
+        # ip.SetBase ("192.168.1.0", "255.255.255.0");
+        ip4 = wrapper.create("Ipv4Address", "192.168.1.0")
+        mask4 = wrapper.create("Ipv4Mask", "255.255.255.0")
+        wrapper.invoke(ip, "SetBase", ip4, mask4)
+
+        # Ipv4InterfaceContainer addresses = ip.Assign (devs);
+        addresses = wrapper.invoke(ip, "Assign", devs)
+
+        ### create pinger
+        #V4PingHelper ping = V4PingHelper (addresses.GetAddress (1));
+        addr1 = wrapper.invoke(addresses, "GetAddress", 1)
+        ping = wrapper.create("V4PingHelper", addr1)
+        btrue = wrapper.create("BooleanValue", True)
+        wrapper.invoke(ping, "SetAttribute", "Verbose", btrue)
+        
+        #apps = ping.Install (pingers);
+        n0 = wrapper.invoke(c, "Get", 0)
+        apps = wrapper.invoke(ping, "Install", n0)
+        
+        #apps.Start (Seconds (0.0));
+        s = wrapper.create ("Seconds", 0.0)
+        wrapper.invoke (apps, "Start", s)
+        
+        #apps.Stop (Seconds (5.0));
+        s = wrapper.create ("Seconds", 5.0)
+        wrapper.invoke (apps, "Stop", s)
+
+        ### run Simulation
+        # Simulator::Stop (6.0);
+        wrapper.stop(time = "6s")
+
+        # Simulator::Run ();
+        wrapper.start()
+
+        # wait until simulation is over
+        wrapper.shutdown()
+
+        # TODO: Add assertions !!
+
+    def test_runtime_attr_modify(self):
+        wrapper = NS3Wrapper()
+       
+        # Define a real time simulation 
+        stype = wrapper.create("StringValue", "ns3::RealtimeSimulatorImpl")
+        wrapper.invoke("singleton::GlobalValue", "Bind", "SimulatorImplementationType", stype)
+        btrue = wrapper.create("BooleanValue", True)
+        wrapper.invoke("singleton::GlobalValue", "Bind", "ChecksumEnabled", btrue)
+
+        ### create 2  nodes
+        ## NODE 1
+        n1 = wrapper.create("Node")
+
+        ## Install internet stack
+        ipv41 = wrapper.create("Ipv4L3Protocol")
+        wrapper.invoke(n1, "AggregateObject", ipv41)
+
+        arp1 = wrapper.create("ArpL3Protocol")
+        wrapper.invoke(n1, "AggregateObject", arp1)
+        
+        icmp1 = wrapper.create("Icmpv4L4Protocol")
+        wrapper.invoke(n1, "AggregateObject", icmp1)
+
+        ## Add IPv4 routing
+        lr1 = wrapper.create("Ipv4ListRouting")
+        wrapper.invoke(ipv41, "SetRoutingProtocol", lr1)
+        sr1 = wrapper.create("Ipv4StaticRouting")
+        wrapper.invoke(lr1, "AddRoutingProtocol", sr1, 1)
+
+        ## NODE 2
+        n2 = wrapper.create("Node")
+
+        ## Install internet stack
+        ipv42 = wrapper.create("Ipv4L3Protocol")
+        wrapper.invoke(n2, "AggregateObject", ipv42)
+
+        arp2 = wrapper.create("ArpL3Protocol")
+        wrapper.invoke(n2, "AggregateObject", arp2)
+        
+        icmp2 = wrapper.create("Icmpv4L4Protocol")
+        wrapper.invoke(n2, "AggregateObject", icmp2)
+
+        ## Add IPv4 routing
+        lr2 = wrapper.create("Ipv4ListRouting")
+        wrapper.invoke(ipv42, "SetRoutingProtocol", lr2)
+        sr2 = wrapper.create("Ipv4StaticRouting")
+        wrapper.invoke(lr2, "AddRoutingProtocol", sr2, 1)
+
+        ##### Create p2p device and enable ascii tracing
+
+        p2pHelper = wrapper.create("PointToPointHelper")
+        asciiHelper = wrapper.create("AsciiTraceHelper")
+
+        # Iface for node1
+        p1 = wrapper.create("PointToPointNetDevice")
+        wrapper.invoke(n1, "AddDevice", p1)
+        q1 = wrapper.create("DropTailQueue")
+        wrapper.invoke(p1, "SetQueue", q1)
+      
+        # Add IPv4 address
+        ifindex1 = wrapper.invoke(ipv41, "AddInterface", p1)
+        mask1 = wrapper.create("Ipv4Mask", "/30")
+        addr1 = wrapper.create("Ipv4Address", "10.0.0.1")
+        inaddr1 = wrapper.create("Ipv4InterfaceAddress", addr1, mask1)
+        wrapper.invoke(ipv41, "AddAddress", ifindex1, inaddr1)
+        wrapper.invoke(ipv41, "SetMetric", ifindex1, 1)
+        wrapper.invoke(ipv41, "SetUp", ifindex1)
+
+        # Enable collection of Ascii format to a specific file
+        filepath1 = "/tmp/trace-p2p-1.tr"
+        stream1 = wrapper.invoke(asciiHelper, "CreateFileStream", filepath1)
+        wrapper.invoke(p2pHelper, "EnableAscii", stream1, p1)
+       
+        # Iface for node2
+        p2 = wrapper.create("PointToPointNetDevice")
+        wrapper.invoke(n2, "AddDevice", p2)
+        q2 = wrapper.create("DropTailQueue")
+        wrapper.invoke(p2, "SetQueue", q2)
+
+        # Add IPv4 address
+        ifindex2 = wrapper.invoke(ipv42, "AddInterface", p2)
+        mask2 = wrapper.create("Ipv4Mask", "/30")
+        addr2 = wrapper.create("Ipv4Address", "10.0.0.2")
+        inaddr2 = wrapper.create("Ipv4InterfaceAddress", addr2, mask2)
+        wrapper.invoke(ipv42, "AddAddress", ifindex2, inaddr2)
+        wrapper.invoke(ipv42, "SetMetric", ifindex2, 1)
+        wrapper.invoke(ipv42, "SetUp", ifindex2)
+
+        # Enable collection of Ascii format to a specific file
+        filepath2 = "/tmp/trace-p2p-2.tr"
+        stream2 = wrapper.invoke(asciiHelper, "CreateFileStream", filepath2)
+        wrapper.invoke(p2pHelper, "EnableAscii", stream2, p2)
+
+        # Create channel
+        chan = wrapper.create("PointToPointChannel")
+        wrapper.set(chan, "Delay", "0s")
+        wrapper.invoke(p1, "Attach", chan)
+        wrapper.invoke(p2, "Attach", chan)
+
+        ### create pinger
+        ping = wrapper.create("V4Ping")
+        wrapper.invoke(n1, "AddApplication", ping)
+        wrapper.set (ping, "Remote", "10.0.0.2")
+        wrapper.set (ping, "Interval", "1s")
+        wrapper.set (ping, "Verbose", True)
+        wrapper.set (ping, "StartTime", "0s")
+        wrapper.set (ping, "StopTime", "20s")
+
+        ### run Simulation
+        wrapper.stop(time = "21s")
+        wrapper.start()
+
+        time.sleep(1)
+
+        wrapper.set(chan, "Delay", "5s")
+
+        time.sleep(5)
+
+        wrapper.set(chan, "Delay", "0s")
+
+        # wait until simulation is over
+        wrapper.shutdown()
+
+        p = subprocess.Popen("rm /tmp/trace-p2p-*",  shell = True)
+        p.communicate()
+        
+        # TODO: Add assertions !!
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/test/resources/planetlab/sfa_node.py b/test/resources/planetlab/sfa_node.py
new file mode 100755 (executable)
index 0000000..cd6e6bb
--- /dev/null
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
+
+from nepi.execution.ec import ExperimentController
+
+from nepi.resources.planetlab.sfa_node import PlanetlabSfaNode
+from nepi.util.sfaapi import SFAAPI, SFAAPIFactory
+
+from test_utils import skipIfNotSfaCredentials
+
+import os
+import time
+import unittest
+import multiprocessing
+
+
+class DummyEC(ExperimentController):
+    pass
+
+class PLSfaNodeFactoryTestCase(unittest.TestCase):
+
+    def test_creation_phase(self):
+        self.assertEquals(PlanetlabSfaNode._rtype, "PlanetlabSfaNode")
+        self.assertEquals(len(PlanetlabSfaNode._attributes), 29)
+
+class PLSfaNodeTestCase(unittest.TestCase):
+    """
+    This tests use inria_nepi slice, from the test instance of MyPLC
+    nepiplc.pl.sophia.inria.fr. This test can fail if the user running
+    the test does not have a user in this instance of MyPLC or is not
+    added to the inria_nepi slice.
+    """
+
+    def setUp(self):
+        self.ec = DummyEC()
+        self.username = os.environ.get('SFA_SLICE')
+        self.sfauser = os.environ.get('SFA_USER')
+        self.sfaPrivateKey = os.environ.get('SFA_PK')
+        
+    @skipIfNotSfaCredentials
+    def test_a_sfaapi(self):
+        """
+        Check that the api to discover and reserve resources is well
+        instanciated, and is an instance of SFAAPI. Check that using
+        the same credentials, the same object of the api is used.
+        """
+        node1 = self.ec.register_resource("PlanetlabSfaNode")
+        self.ec.set(node1, "hostname", "planetlab2.ionio.gr")
+        self.ec.set(node1, "username", self.username)
+        self.ec.set(node1, "sfauser", self.sfauser)
+        self.ec.set(node1, "sfaPrivateKey", self.sfaPrivateKey)
+
+        plnode_rm1 = self.ec.get_resource(node1)
+
+        self.assertIsNone(plnode_rm1._node_to_provision)
+
+        api1 = plnode_rm1.sfaapi
+        self.assertIsInstance(api1, SFAAPI)
+        self.assertEquals(len(api1.reserved()), 0)
+        self.assertEquals(len(api1.blacklisted()), 0)
+
+        node2 = self.ec.register_resource("PlanetlabSfaNode")
+        self.ec.set(node2, "hostname", "planetlab2.ionio.gr")
+        self.ec.set(node2, "username", self.username)
+        self.ec.set(node2, "sfauser", self.sfauser)
+        self.ec.set(node2, "sfaPrivateKey", self.sfaPrivateKey)
+
+        plnode_rm2 = self.ec.get_resource(node2)
+        api2 = plnode_rm2.sfaapi
+        self.assertEquals(api1, api2)
+    
+    @skipIfNotSfaCredentials
+    def test_discover(self):
+        """
+        Check that the method do_discover reserve the right node.
+        """
+        node = self.ec.register_resource("PlanetlabSfaNode")
+        self.ec.set(node, "hostname", "planetlab2.ionio.gr")
+        self.ec.set(node, "username", self.username)
+        self.ec.set(node, "sfauser", self.sfauser)
+        self.ec.set(node, "sfaPrivateKey", self.sfaPrivateKey)
+
+        plnode_rm = self.ec.get_resource(node)
+       
+        hostname = plnode_rm.get("hostname")
+        self.assertIsNotNone(hostname)
+
+        self.assertEquals(plnode_rm.sfaapi.reserved(), set())
+
+        plnode_rm.do_discover()
+        self.assertEquals(plnode_rm.sfaapi.reserved().pop(), 'ple.dbislab.planetlab2.ionio.gr')
+        self.assertEquals(plnode_rm._node_to_provision, 'ple.dbislab.planetlab2.ionio.gr')
+
+    @skipIfNotSfaCredentials
+    def test_provision(self):
+        """
+        This test checks that the method do_provision add the node in the slice and check
+        its well functioning.
+        """
+        node = self.ec.register_resource("PlanetlabSfaNode")
+        self.ec.set(node, "hostname", "planetlab2.ionio.gr")
+        self.ec.set(node, "username", self.username)
+        self.ec.set(node, "sfauser", self.sfauser)
+        self.ec.set(node, "sfaPrivateKey", self.sfaPrivateKey)
+
+        plnode_rm = self.ec.get_resource(node)
+
+        self.assertEquals(plnode_rm.sfaapi.reserved(), set())
+        self.assertIsNone(plnode_rm._node_to_provision)
+
+        slicename = 'ple.' + self.username.replace('_', '.')
+
+        plnode_rm.do_discover()
+        plnode_rm.do_provision()    
+
+        cmd = 'echo "IT WORKED"'
+        ((out, err), proc) = plnode_rm.execute(cmd)
+        self.assertEquals(out.strip(), "IT WORKED")
+
+        urn_to_delete = 'urn:publicid:IDN+ple:dbislab+node+planetlab2.ionio.gr'
+        plnode_rm.sfaapi.remove_resource_from_slice(slicename, urn_to_delete)
+
+        slice_resources = plnode_rm.sfaapi.get_slice_resources(slicename)['resource']
+        if slice_resources:
+            slice_resources_hrn = plnode_rm.sfaapi.get_resources_hrn(slice_resources)
+            self.assertNotIn('planetlab2.ionio.gr', slice_resources_hrn.keys())           
+
+    @skipIfNotSfaCredentials
+    def test_xdeploy(self):
+        """
+        Test with the nodes being discover and provision at the same time.
+        The deploy should fail as the test before, there aren't 4 nodes of 
+        that carachteristics.
+        """
+        node = self.ec.register_resource("PlanetlabSfaNode")
+        self.ec.set(node, "hostname", "planetlab2.ionio.gr")
+        self.ec.set(node, "username", self.username)
+        self.ec.set(node, "sfauser", self.sfauser)
+        self.ec.set(node, "sfaPrivateKey", self.sfaPrivateKey)
+
+        self.ec.deploy()
+        self.ec.wait_deployed(node)
+        state = self.ec.state(node)
+        self.assertEquals(state, 3)
+
+    def tearDown(self):
+        self.ec.shutdown()
+
+
+if __name__ == '__main__':
+    unittest.main()
+
+
+
index 1a55b6b..88f2eb2 100755 (executable)
@@ -184,7 +184,7 @@ class SSHfuncsTestCase(unittest.TestCase):
 
         self.assertEquals(outlocal, outremote)
 
-    def test_rcopy(self):
+    def test_rcopy_list(self):
         env = test_environment()
         user = getpass.getuser()
         host = "localhost"
@@ -212,6 +212,38 @@ class SSHfuncsTestCase(unittest.TestCase):
 
         self.assertEquals(sorted(origfiles), sorted(files))
 
+        os.remove(f1.name)
+        shutil.rmtree(dirpath)
+
+    def test_rcopy_list(self):
+        env = test_environment()
+        user = getpass.getuser()
+        host = "localhost"
+
+        # create some temp files and directories to copy
+        dirpath = tempfile.mkdtemp()
+        f = tempfile.NamedTemporaryFile(dir=dirpath, delete=False)
+        f.close()
+      
+        f1 = tempfile.NamedTemporaryFile(delete=False)
+        f1.close()
+        f1.name
+
+        # Copy a list of files
+        source = [dirpath, f1.name]
+        destdir = tempfile.mkdtemp()
+        dest = "%s@%s:%s" % (user, host, destdir)
+        ((out, err), proc) = rcopy(source, dest, port = env.port, agent = True, recursive = True)
+
+        files = []
+        def recls(files, dirname, names):
+            files.extend(names)
+        os.path.walk(destdir, recls, files)
+       
+        origfiles = map(lambda s: os.path.basename(s), [dirpath, f.name, f1.name])
+
+        self.assertEquals(sorted(origfiles), sorted(files))
+
     def test_rproc_manage(self):
         env = test_environment()
         user = getpass.getuser()
diff --git a/test/util/timefuncs.py b/test/util/timefuncs.py
new file mode 100755 (executable)
index 0000000..8836c79
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
+
+from test_utils import skipIfNotPythonVersion
+
+import datetime
+import unittest
+
+def _get_total_seconds(td):
+    return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 1e6) / 1e6
+
+class TimeFuncTestCase(unittest.TestCase):
+
+    @skipIfNotPythonVersion
+    def test_total_seconds(self):
+        date = datetime.timedelta(2, 468, 506260)
+        seconds1 = _get_total_seconds(date)
+        seconds2 = date.total_seconds()
+
+        self.assertEquals(seconds1, seconds2)
+
+
+if __name__ == '__main__':
+    unittest.main()
+
+