From 590481ab47520f9bfdfda34630408a09a770f5a1 Mon Sep 17 00:00:00 2001 From: Alina Quereilhac Date: Thu, 26 Mar 2015 19:49:13 +0100 Subject: [PATCH] add sphinx documentation --- doc/sphinx/Makefile | 153 + .../_build/doctrees/_layout/modules.doctree | Bin 0 -> 2721 bytes .../_build/doctrees/_layout/nepi.data.doctree | Bin 0 -> 3588 bytes .../_layout/nepi.data.processing.ccn.doctree | Bin 0 -> 23918 bytes .../_layout/nepi.data.processing.doctree | Bin 0 -> 3739 bytes .../_layout/nepi.data.processing.ping.doctree | Bin 0 -> 10408 bytes .../_build/doctrees/_layout/nepi.doctree | Bin 0 -> 3634 bytes .../doctrees/_layout/nepi.execution.doctree | Bin 0 -> 620283 bytes .../_layout/nepi.resources.all.doctree | Bin 0 -> 16477 bytes .../doctrees/_layout/nepi.resources.doctree | Bin 0 -> 3838 bytes .../_layout/nepi.resources.linux.ccn.doctree | Bin 0 -> 99708 bytes .../_layout/nepi.resources.linux.doctree | Bin 0 -> 433963 bytes .../nepi.resources.linux.netns.doctree | Bin 0 -> 54967 bytes .../nepi.resources.linux.ns3.ccn.doctree | Bin 0 -> 30797 bytes .../_layout/nepi.resources.linux.ns3.doctree | Bin 0 -> 127381 bytes .../_layout/nepi.resources.netns.doctree | Bin 0 -> 152253 bytes .../nepi.resources.ns3.classes.doctree | Bin 0 -> 490090 bytes .../_layout/nepi.resources.ns3.doctree | Bin 0 -> 377819 bytes .../_layout/nepi.resources.omf.doctree | Bin 0 -> 373627 bytes .../_layout/nepi.resources.planetlab.doctree | Bin 0 -> 143676 bytes .../nepi.resources.planetlab.ns3.doctree | Bin 0 -> 16927 bytes ...pi.resources.planetlab.openvswitch.doctree | Bin 0 -> 59649 bytes .../_build/doctrees/_layout/nepi.util.doctree | Bin 0 -> 315318 bytes .../_layout/nepi.util.parsers.doctree | Bin 0 -> 15545 bytes doc/sphinx/_build/doctrees/environment.pickle | Bin 0 -> 3275437 bytes doc/sphinx/_build/doctrees/index.doctree | Bin 0 -> 21584 bytes doc/sphinx/_build/html/.buildinfo | 4 + doc/sphinx/_build/html/_layout/modules.html | 150 + doc/sphinx/_build/html/_layout/nepi.data.html | 134 + .../_layout/nepi.data.processing.ccn.html | 174 + .../html/_layout/nepi.data.processing.html | 127 + .../_layout/nepi.data.processing.ping.html | 133 + .../_build/html/_layout/nepi.execution.html | 2376 +++++ doc/sphinx/_build/html/_layout/nepi.html | 483 + .../html/_layout/nepi.resources.all.html | 165 + .../_build/html/_layout/nepi.resources.html | 409 + .../_layout/nepi.resources.linux.ccn.html | 446 + .../html/_layout/nepi.resources.linux.html | 1539 +++ .../_layout/nepi.resources.linux.netns.html | 285 + .../_layout/nepi.resources.linux.ns3.ccn.html | 186 + .../_layout/nepi.resources.linux.ns3.html | 536 + .../html/_layout/nepi.resources.netns.html | 617 ++ .../_layout/nepi.resources.ns3.classes.html | 1171 ++ .../html/_layout/nepi.resources.ns3.html | 1239 +++ .../html/_layout/nepi.resources.omf.html | 1597 +++ .../_layout/nepi.resources.planetlab.html | 629 ++ .../_layout/nepi.resources.planetlab.ns3.html | 153 + .../nepi.resources.planetlab.openvswitch.html | 321 + doc/sphinx/_build/html/_layout/nepi.util.html | 1227 +++ .../html/_layout/nepi.util.parsers.html | 151 + doc/sphinx/_build/html/_modules/index.html | 330 + .../nepi/data/processing/ccn/parser.html | 505 + .../nepi/data/processing/ping/parser.html | 212 + .../_modules/nepi/execution/attribute.html | 286 + .../html/_modules/nepi/execution/ec.html | 1365 +++ .../_modules/nepi/execution/resource.html | 1326 +++ .../html/_modules/nepi/execution/runner.html | 267 + .../_modules/nepi/execution/scheduler.html | 201 + .../html/_modules/nepi/execution/trace.html | 148 + .../nepi/resources/all/collector.html | 227 + .../nepi/resources/linux/application.html | 860 ++ .../resources/linux/ccn/ccnapplication.html | 159 + .../nepi/resources/linux/ccn/ccncat.html | 163 + .../nepi/resources/linux/ccn/ccncontent.html | 241 + .../nepi/resources/linux/ccn/ccnd.html | 442 + .../nepi/resources/linux/ccn/ccnpeek.html | 155 + .../nepi/resources/linux/ccn/ccnping.html | 186 + .../resources/linux/ccn/ccnpingserver.html | 225 + .../nepi/resources/linux/ccn/ccnpoke.html | 163 + .../nepi/resources/linux/ccn/ccnr.html | 397 + .../nepi/resources/linux/ccn/fibentry.html | 367 + .../nepi/resources/linux/channel.html | 129 + .../nepi/resources/linux/debfuncs.html | 133 + .../nepi/resources/linux/gretunnel.html | 177 + .../nepi/resources/linux/interface.html | 402 + .../_modules/nepi/resources/linux/mtr.html | 240 + .../resources/linux/netns/netnsclient.html | 198 + .../resources/linux/netns/netnsemulation.html | 473 + .../_modules/nepi/resources/linux/node.html | 1216 +++ .../_modules/nepi/resources/linux/nping.html | 312 + .../ns3/ccn/ns3ccncatdceapplication.html | 153 + .../linux/ns3/ccn/ns3ccndceapplication.html | 198 + .../linux/ns3/ccn/ns3ccnddceapplication.html | 295 + .../ns3/ccn/ns3ccnpeekdceapplication.html | 136 + .../ns3/ccn/ns3ccnpokedceapplication.html | 155 + .../linux/ns3/ccn/ns3ccnrdceapplication.html | 319 + .../ns3/ccn/ns3fibentrydceapplication.html | 196 + .../nepi/resources/linux/ns3/fdudptunnel.html | 473 + .../nepi/resources/linux/ns3/ns3client.html | 208 + .../linux/ns3/ns3dceapplication.html | 170 + .../linux/ns3/ns3pingdceapplication.html | 345 + .../resources/linux/ns3/ns3simulation.html | 827 ++ .../resources/linux/ns3/tuntapfdlink.html | 251 + .../_modules/nepi/resources/linux/ping.html | 372 + .../_modules/nepi/resources/linux/route.html | 251 + .../nepi/resources/linux/rpmfuncs.html | 161 + .../_modules/nepi/resources/linux/tap.html | 710 ++ .../nepi/resources/linux/tcpdump.html | 499 + .../nepi/resources/linux/traceroute.html | 217 + .../_modules/nepi/resources/linux/tun.html | 127 + .../_modules/nepi/resources/linux/tunnel.html | 256 + .../nepi/resources/linux/udptest.html | 461 + .../nepi/resources/linux/udptunnel.html | 245 + .../resources/netns/netnsapplication.html | 190 + .../nepi/resources/netns/netnsbase.html | 230 + .../nepi/resources/netns/netnsclient.html | 132 + .../nepi/resources/netns/netnsemulation.html | 132 + .../nepi/resources/netns/netnsinterface.html | 117 + .../resources/netns/netnsipv4address.html | 153 + .../nepi/resources/netns/netnsnode.html | 137 + .../resources/netns/netnsnodeinterface.html | 157 + .../nepi/resources/netns/netnsroute.html | 152 + .../nepi/resources/netns/netnsserver.html | 307 + .../nepi/resources/netns/netnsswitch.html | 153 + .../nepi/resources/netns/netnswrapper.html | 280 + .../resources/netns/netnswrapper_debug.html | 251 + .../ns3/classes/aarf_wifi_manager.html | 268 + .../ns3/classes/aarfcd_wifi_manager.html | 308 + .../resources/ns3/classes/adhoc_wifi_mac.html | 300 + .../ns3/classes/aloha_noack_net_device.html | 168 + .../ns3/classes/amrr_wifi_manager.html | 268 + .../resources/ns3/classes/ap_wifi_mac.html | 340 + .../ns3/classes/arf_wifi_manager.html | 238 + .../resources/ns3/classes/arp_l3protocol.html | 146 + .../ns3/classes/base_station_net_device.html | 260 + .../ns3/classes/binary_error_model.html | 141 + .../classes/binary_error_sixlow_model.html | 141 + .../resources/ns3/classes/bridge_channel.html | 141 + .../ns3/classes/bridge_net_device.html | 161 + .../ns3/classes/bulk_send_application.html | 196 + .../ns3/classes/burst_error_model.html | 171 + .../ns3/classes/cara_wifi_manager.html | 258 + .../constant_acceleration_mobility_model.html | 156 + .../constant_position_mobility_model.html | 156 + .../classes/constant_rate_wifi_manager.html | 238 + ...onstant_speed_propagation_delay_model.html | 141 + .../constant_velocity_mobility_model.html | 156 + .../cost231propagation_loss_model.html | 181 + .../resources/ns3/classes/csma_channel.html | 161 + .../ns3/classes/csma_net_device.html | 220 + .../ns3/classes/drop_tail_queue.html | 164 + .../resources/ns3/classes/dsrdsr_routing.html | 540 + .../resources/ns3/classes/emu_net_device.html | 216 + .../resources/ns3/classes/error_channel.html | 141 + .../ns3/classes/error_channel_sixlow.html | 141 + .../ns3/classes/error_net_device.html | 135 + .../resources/ns3/classes/fd_net_device.html | 206 + .../ns3/classes/fixed_rss_loss_model.html | 141 + .../classes/friis_propagation_loss_model.html | 161 + .../classes/gauss_markov_mobility_model.html | 246 + .../classes/hierarchical_mobility_model.html | 156 + ...brid_buildings_propagation_loss_model.html | 181 + .../ns3/classes/icmpv4l4protocol.html | 141 + .../ns3/classes/icmpv6l4protocol.html | 161 + .../ns3/classes/ideal_wifi_manager.html | 228 + .../resources/ns3/classes/ipv4l3protocol.html | 206 + .../itu_r1411los_propagation_loss_model.html | 130 + ...s_over_rooftop_propagation_loss_model.html | 201 + .../classes/jakes_propagation_loss_model.html | 130 + .../kun2600mhz_propagation_loss_model.html | 130 + .../ns3/classes/list_error_model.html | 141 + .../log_distance_propagation_loss_model.html | 161 + .../ns3/classes/loopback_net_device.html | 130 + .../ns3/classes/lr_wpan_net_device.html | 141 + .../ns3/classes/lte_enb_net_device.html | 211 + .../ns3/classes/lte_simple_net_device.html | 135 + .../ns3/classes/lte_ue_net_device.html | 171 + .../matrix_propagation_loss_model.html | 141 + .../ns3/classes/mesh_point_device.html | 141 + .../ns3/classes/mesh_wifi_interface_mac.html | 330 + .../ns3/classes/minstrel_wifi_manager.html | 268 + .../classes/multi_model_spectrum_channel.html | 156 + .../nakagami_propagation_loss_model.html | 201 + .../ns3/classes/nist_error_rate_model.html | 130 + .../nepi/resources/ns3/classes/node.html | 151 + .../classes/non_communicating_net_device.html | 130 + .../resources/ns3/classes/ocb_wifi_mac.html | 300 + .../oh_buildings_propagation_loss_model.html | 171 + .../okumura_hata_propagation_loss_model.html | 161 + .../ns3/classes/on_off_application.html | 226 + .../ns3/classes/onoe_wifi_manager.html | 248 + .../resources/ns3/classes/packet_sink.html | 176 + .../nepi/resources/ns3/classes/ping6.html | 201 + .../ns3/classes/point_to_point_channel.html | 156 + .../classes/point_to_point_net_device.html | 216 + .../point_to_point_remote_channel.html | 156 + .../nepi/resources/ns3/classes/radvd.html | 161 + .../random_direction2d_mobility_model.html | 186 + .../random_propagation_delay_model.html | 141 + .../random_propagation_loss_model.html | 141 + .../classes/random_walk2d_mobility_model.html | 216 + .../random_waypoint_mobility_model.html | 176 + .../classes/range_propagation_loss_model.html | 141 + .../ns3/classes/rate_error_model.html | 171 + .../ns3/classes/receive_list_error_model.html | 141 + .../nepi/resources/ns3/classes/red_queue.html | 264 + .../ns3/classes/rraa_wifi_manager.html | 458 + .../resources/ns3/classes/simple_channel.html | 141 + .../ns3/classes/simple_net_device.html | 135 + .../single_model_spectrum_channel.html | 156 + .../ns3/classes/six_low_pan_net_device.html | 214 + .../resources/ns3/classes/sta_wifi_mac.html | 348 + ..._state_random_waypoint_mobility_model.html | 246 + .../subscriber_station_net_device.html | 306 + .../resources/ns3/classes/tap_bridge.html | 211 + .../resources/ns3/classes/tcp_l4protocol.html | 161 + ...e_log_distance_propagation_loss_model.html | 201 + ...two_ray_ground_propagation_loss_model.html | 171 + .../resources/ns3/classes/uan_channel.html | 141 + .../resources/ns3/classes/udp_client.html | 201 + .../ns3/classes/udp_echo_client.html | 206 + .../ns3/classes/udp_echo_server.html | 161 + .../resources/ns3/classes/udp_l4protocol.html | 141 + .../resources/ns3/classes/udp_server.html | 171 + .../ns3/classes/udp_trace_client.html | 181 + .../nepi/resources/ns3/classes/v4ping.html | 196 + .../ns3/classes/virtual_net_device.html | 162 + .../ns3/classes/waypoint_mobility_model.html | 186 + .../ns3/classes/wifi_net_device.html | 141 + .../ns3/classes/yans_error_rate_model.html | 130 + .../ns3/classes/yans_wifi_channel.html | 141 + .../resources/ns3/classes/yans_wifi_phy.html | 344 + .../nepi/resources/ns3/ns3application.html | 181 + .../nepi/resources/ns3/ns3arpl3protocol.html | 137 + .../_modules/nepi/resources/ns3/ns3base.html | 257 + .../resources/ns3/ns3ccndceapplication.html | 212 + .../nepi/resources/ns3/ns3channel.html | 141 + .../nepi/resources/ns3/ns3client.html | 141 + .../nepi/resources/ns3/ns3dceapplication.html | 272 + .../nepi/resources/ns3/ns3dcehelper.html | 149 + .../nepi/resources/ns3/ns3errormodel.html | 140 + .../nepi/resources/ns3/ns3errorratemodel.html | 144 + .../nepi/resources/ns3/ns3fdnetdevice.html | 149 + .../resources/ns3/ns3icmpv4l4protocol.html | 134 + .../nepi/resources/ns3/ns3ipv4l3protocol.html | 157 + .../nepi/resources/ns3/ns3mobilitymodel.html | 135 + .../nepi/resources/ns3/ns3netdevice.html | 313 + .../_modules/nepi/resources/ns3/ns3node.html | 285 + .../nepi/resources/ns3/ns3pipechanel.html | 171 + .../ns3/ns3propagationdelaymodel.html | 144 + .../ns3/ns3propagationlossmodel.html | 144 + .../_modules/nepi/resources/ns3/ns3queue.html | 145 + .../_modules/nepi/resources/ns3/ns3route.html | 183 + .../nepi/resources/ns3/ns3server.html | 349 + .../nepi/resources/ns3/ns3simulation.html | 141 + .../nepi/resources/ns3/ns3wifichannel.html | 141 + .../nepi/resources/ns3/ns3wifimac.html | 169 + .../nepi/resources/ns3/ns3wifinetdevice.html | 144 + .../nepi/resources/ns3/ns3wifiphy.html | 178 + .../ns3/ns3wifiremotestationmanager.html | 145 + .../nepi/resources/ns3/ns3wrapper.html | 795 ++ .../nepi/resources/ns3/ns3wrapper_debug.html | 271 + .../ns3/resource_manager_generator.html | 330 + .../nepi/resources/omf/application.html | 510 + .../_modules/nepi/resources/omf/channel.html | 291 + .../nepi/resources/omf/interface.html | 430 + .../nepi/resources/omf/messages_5_4.html | 345 + .../nepi/resources/omf/messages_6.html | 343 + .../_modules/nepi/resources/omf/node.html | 267 + .../_modules/nepi/resources/omf/omf5_api.html | 402 + .../_modules/nepi/resources/omf/omf6_api.html | 351 + .../nepi/resources/omf/omf6_parser.html | 382 + .../nepi/resources/omf/omf_api_factory.html | 230 + .../nepi/resources/omf/omf_client.html | 449 + .../nepi/resources/omf/omf_resource.html | 167 + .../nepi/resources/omf/wilabt_node.html | 559 + .../nepi/resources/planetlab/node.html | 775 ++ .../resources/planetlab/ns3/fdudptunnel.html | 164 + .../resources/planetlab/ns3/tuntapfdlink.html | 183 + .../resources/planetlab/openvswitch/ovs.html | 406 + .../planetlab/openvswitch/ovsport.html | 384 + .../nepi/resources/planetlab/plcapi.html | 676 ++ .../nepi/resources/planetlab/sfa_node.html | 762 ++ .../nepi/resources/planetlab/tap.html | 413 + .../nepi/resources/planetlab/tun.html | 129 + .../nepi/resources/planetlab/vroute.html | 276 + .../html/_modules/nepi/util/environ.html | 293 + .../html/_modules/nepi/util/execfuncs.html | 356 + .../_build/html/_modules/nepi/util/guid.html | 123 + .../html/_modules/nepi/util/logger.html | 145 + .../html/_modules/nepi/util/manifoldapi.html | 361 + .../html/_modules/nepi/util/netgraph.html | 434 + .../html/_modules/nepi/util/parallel.html | 255 + .../nepi/util/parsers/xml_parser.html | 549 + .../html/_modules/nepi/util/plotter.html | 198 + .../html/_modules/nepi/util/rmatcher.html | 155 + .../html/_modules/nepi/util/serializer.html | 151 + .../html/_modules/nepi/util/sfaapi.html | 562 + .../_modules/nepi/util/sfarspec_proc.html | 312 + .../html/_modules/nepi/util/sshfuncs.html | 988 ++ .../html/_modules/nepi/util/statfuncs.html | 136 + .../html/_modules/nepi/util/timefuncs.html | 213 + .../_build/html/_sources/_layout/modules.txt | 7 + .../_layout/nepi.data.processing.ccn.txt | 22 + .../_layout/nepi.data.processing.ping.txt | 22 + .../_sources/_layout/nepi.data.processing.txt | 18 + .../html/_sources/_layout/nepi.data.txt | 17 + .../html/_sources/_layout/nepi.execution.txt | 70 + .../_sources/_layout/nepi.resources.all.txt | 22 + .../_layout/nepi.resources.linux.ccn.txt | 94 + .../_layout/nepi.resources.linux.netns.txt | 30 + .../_layout/nepi.resources.linux.ns3.ccn.txt | 70 + .../_layout/nepi.resources.linux.ns3.txt | 69 + .../_sources/_layout/nepi.resources.linux.txt | 167 + .../_sources/_layout/nepi.resources.netns.txt | 118 + .../_layout/nepi.resources.ns3.classes.txt | 862 ++ .../_sources/_layout/nepi.resources.ns3.txt | 269 + .../_sources/_layout/nepi.resources.omf.txt | 118 + .../_layout/nepi.resources.planetlab.ns3.txt | 30 + .../nepi.resources.planetlab.openvswitch.txt | 30 + .../_layout/nepi.resources.planetlab.txt | 70 + .../html/_sources/_layout/nepi.resources.txt | 22 + .../_build/html/_sources/_layout/nepi.txt | 20 + .../_sources/_layout/nepi.util.parsers.txt | 22 + .../html/_sources/_layout/nepi.util.txt | 141 + doc/sphinx/_build/html/_sources/index.txt | 91 + .../_build/html/_static/ajax-loader.gif | Bin 0 -> 673 bytes doc/sphinx/_build/html/_static/basic.css | 537 + .../_build/html/_static/comment-bright.png | Bin 0 -> 3500 bytes .../_build/html/_static/comment-close.png | Bin 0 -> 3578 bytes doc/sphinx/_build/html/_static/comment.png | Bin 0 -> 3445 bytes doc/sphinx/_build/html/_static/contents.png | Bin 0 -> 202 bytes doc/sphinx/_build/html/_static/doctools.js | 238 + .../_build/html/_static/down-pressed.png | Bin 0 -> 368 bytes doc/sphinx/_build/html/_static/down.png | Bin 0 -> 363 bytes doc/sphinx/_build/html/_static/file.png | Bin 0 -> 392 bytes doc/sphinx/_build/html/_static/jquery.js | 9404 +++++++++++++++++ doc/sphinx/_build/html/_static/minus.png | Bin 0 -> 199 bytes doc/sphinx/_build/html/_static/navigation.png | Bin 0 -> 218 bytes doc/sphinx/_build/html/_static/plus.png | Bin 0 -> 199 bytes doc/sphinx/_build/html/_static/pygments.css | 62 + doc/sphinx/_build/html/_static/searchtools.js | 622 ++ doc/sphinx/_build/html/_static/sphinxdoc.css | 339 + doc/sphinx/_build/html/_static/underscore.js | 1226 +++ doc/sphinx/_build/html/_static/up-pressed.png | Bin 0 -> 372 bytes doc/sphinx/_build/html/_static/up.png | Bin 0 -> 363 bytes doc/sphinx/_build/html/_static/websupport.js | 808 ++ doc/sphinx/_build/html/genindex.html | 7100 +++++++++++++ doc/sphinx/_build/html/index.html | 201 + doc/sphinx/_build/html/objects.inv | Bin 0 -> 16497 bytes doc/sphinx/_build/html/py-modindex.html | 1424 +++ doc/sphinx/_build/html/search.html | 105 + doc/sphinx/_build/html/searchindex.js | 1 + doc/sphinx/_layout/modules.rst | 7 + .../_layout/nepi.data.processing.ccn.rst | 22 + .../_layout/nepi.data.processing.ping.rst | 22 + doc/sphinx/_layout/nepi.data.processing.rst | 18 + doc/sphinx/_layout/nepi.data.rst | 17 + doc/sphinx/_layout/nepi.execution.rst | 70 + doc/sphinx/_layout/nepi.resources.all.rst | 22 + .../_layout/nepi.resources.linux.ccn.rst | 94 + .../_layout/nepi.resources.linux.netns.rst | 30 + .../_layout/nepi.resources.linux.ns3.ccn.rst | 70 + .../_layout/nepi.resources.linux.ns3.rst | 69 + doc/sphinx/_layout/nepi.resources.linux.rst | 167 + doc/sphinx/_layout/nepi.resources.netns.rst | 118 + .../_layout/nepi.resources.ns3.classes.rst | 862 ++ doc/sphinx/_layout/nepi.resources.ns3.rst | 269 + doc/sphinx/_layout/nepi.resources.omf.rst | 118 + .../_layout/nepi.resources.planetlab.ns3.rst | 30 + .../nepi.resources.planetlab.openvswitch.rst | 30 + .../_layout/nepi.resources.planetlab.rst | 70 + doc/sphinx/_layout/nepi.resources.rst | 22 + doc/sphinx/_layout/nepi.rst | 20 + doc/sphinx/_layout/nepi.util.parsers.rst | 22 + doc/sphinx/_layout/nepi.util.rst | 141 + doc/sphinx/conf.py | 247 + doc/sphinx/index.rst | 91 + 368 files changed, 103370 insertions(+) create mode 100644 doc/sphinx/Makefile create mode 100644 doc/sphinx/_build/doctrees/_layout/modules.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.data.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ccn.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.data.processing.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ping.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.execution.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.all.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ccn.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.netns.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.ccn.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.netns.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.classes.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.omf.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.ns3.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.openvswitch.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.util.doctree create mode 100644 doc/sphinx/_build/doctrees/_layout/nepi.util.parsers.doctree create mode 100644 doc/sphinx/_build/doctrees/environment.pickle create mode 100644 doc/sphinx/_build/doctrees/index.doctree create mode 100644 doc/sphinx/_build/html/.buildinfo create mode 100644 doc/sphinx/_build/html/_layout/modules.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.data.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.data.processing.ccn.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.data.processing.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.data.processing.ping.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.execution.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.all.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.ccn.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.netns.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.ccn.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.netns.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.ns3.classes.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.ns3.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.omf.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.planetlab.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.planetlab.ns3.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.resources.planetlab.openvswitch.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.util.html create mode 100644 doc/sphinx/_build/html/_layout/nepi.util.parsers.html create mode 100644 doc/sphinx/_build/html/_modules/index.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/data/processing/ccn/parser.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/data/processing/ping/parser.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/attribute.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/ec.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/resource.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/runner.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/scheduler.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/execution/trace.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/all/collector.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncat.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncontent.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnd.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpeek.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnping.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpingserver.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpoke.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnr.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/fibentry.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/debfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/gretunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/interface.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/mtr.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsclient.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsemulation.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/nping.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccncatdceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccndceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnddceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpeekdceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpokedceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnrdceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3fibentrydceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/fdudptunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3dceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3pingdceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3simulation.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/tuntapfdlink.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/ping.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/route.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/rpmfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/tap.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/tcpdump.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/traceroute.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/tun.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/tunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/udptest.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/linux/udptunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsbase.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsclient.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsemulation.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsinterface.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsipv4address.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnode.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnodeinterface.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsroute.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsserver.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsswitch.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper_debug.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarf_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarfcd_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/adhoc_wifi_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aloha_noack_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/amrr_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ap_wifi_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arf_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arp_l3protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/base_station_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_sixlow_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bulk_send_application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/burst_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cara_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_acceleration_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_position_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_rate_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_velocity_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cost231propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/drop_tail_queue.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/dsrdsr_routing.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/emu_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel_sixlow.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fd_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fixed_rss_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/friis_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/gauss_markov_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hierarchical_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv4l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv6l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ideal_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ipv4l3protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411los_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411nlos_over_rooftop_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/jakes_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/kun2600mhz_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/list_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/log_distance_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/loopback_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lr_wpan_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_enb_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_simple_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_ue_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/matrix_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_point_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_wifi_interface_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/minstrel_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/multi_model_spectrum_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nakagami_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nist_error_rate_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/non_communicating_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ocb_wifi_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/okumura_hata_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/on_off_application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/onoe_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/packet_sink.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ping6.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_remote_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/radvd.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_direction2d_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_delay_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_walk2d_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_waypoint_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/range_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rate_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/receive_list_error_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/red_queue.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rraa_wifi_manager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/single_model_spectrum_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/six_low_pan_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/sta_wifi_mac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/subscriber_station_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tap_bridge.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tcp_l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/uan_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_server.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_server.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_trace_client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/v4ping.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/virtual_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/waypoint_mobility_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/wifi_net_device.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_error_rate_model.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_phy.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3arpl3protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3base.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ccndceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dceapplication.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dcehelper.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errormodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errorratemodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3fdnetdevice.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3icmpv4l4protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ipv4l3protocol.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3mobilitymodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3netdevice.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3pipechanel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationdelaymodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationlossmodel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3queue.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3route.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3server.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3simulation.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifichannel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifimac.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifinetdevice.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiphy.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiremotestationmanager.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper_debug.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/ns3/resource_manager_generator.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/application.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/channel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/interface.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_5_4.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_6.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf5_api.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_api.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_parser.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_api_factory.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_client.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_resource.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/omf/wilabt_node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/fdudptunnel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/tuntapfdlink.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovsport.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/plcapi.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/sfa_node.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tap.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tun.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/resources/planetlab/vroute.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/environ.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/execfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/guid.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/logger.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/manifoldapi.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/netgraph.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/parallel.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/parsers/xml_parser.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/plotter.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/rmatcher.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/serializer.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/sfaapi.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/sfarspec_proc.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/sshfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/statfuncs.html create mode 100644 doc/sphinx/_build/html/_modules/nepi/util/timefuncs.html create mode 100644 doc/sphinx/_build/html/_sources/_layout/modules.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ccn.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ping.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.data.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.execution.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.all.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ccn.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.netns.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.ccn.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.netns.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.classes.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.omf.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.ns3.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.openvswitch.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.resources.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.util.parsers.txt create mode 100644 doc/sphinx/_build/html/_sources/_layout/nepi.util.txt create mode 100644 doc/sphinx/_build/html/_sources/index.txt create mode 100644 doc/sphinx/_build/html/_static/ajax-loader.gif create mode 100644 doc/sphinx/_build/html/_static/basic.css create mode 100644 doc/sphinx/_build/html/_static/comment-bright.png create mode 100644 doc/sphinx/_build/html/_static/comment-close.png create mode 100644 doc/sphinx/_build/html/_static/comment.png create mode 100644 doc/sphinx/_build/html/_static/contents.png create mode 100644 doc/sphinx/_build/html/_static/doctools.js create mode 100644 doc/sphinx/_build/html/_static/down-pressed.png create mode 100644 doc/sphinx/_build/html/_static/down.png create mode 100644 doc/sphinx/_build/html/_static/file.png create mode 100644 doc/sphinx/_build/html/_static/jquery.js create mode 100644 doc/sphinx/_build/html/_static/minus.png create mode 100644 doc/sphinx/_build/html/_static/navigation.png create mode 100644 doc/sphinx/_build/html/_static/plus.png create mode 100644 doc/sphinx/_build/html/_static/pygments.css create mode 100644 doc/sphinx/_build/html/_static/searchtools.js create mode 100644 doc/sphinx/_build/html/_static/sphinxdoc.css create mode 100644 doc/sphinx/_build/html/_static/underscore.js create mode 100644 doc/sphinx/_build/html/_static/up-pressed.png create mode 100644 doc/sphinx/_build/html/_static/up.png create mode 100644 doc/sphinx/_build/html/_static/websupport.js create mode 100644 doc/sphinx/_build/html/genindex.html create mode 100644 doc/sphinx/_build/html/index.html create mode 100644 doc/sphinx/_build/html/objects.inv create mode 100644 doc/sphinx/_build/html/py-modindex.html create mode 100644 doc/sphinx/_build/html/search.html create mode 100644 doc/sphinx/_build/html/searchindex.js create mode 100644 doc/sphinx/_layout/modules.rst create mode 100644 doc/sphinx/_layout/nepi.data.processing.ccn.rst create mode 100644 doc/sphinx/_layout/nepi.data.processing.ping.rst create mode 100644 doc/sphinx/_layout/nepi.data.processing.rst create mode 100644 doc/sphinx/_layout/nepi.data.rst create mode 100644 doc/sphinx/_layout/nepi.execution.rst create mode 100644 doc/sphinx/_layout/nepi.resources.all.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.ccn.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.netns.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.ns3.ccn.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.ns3.rst create mode 100644 doc/sphinx/_layout/nepi.resources.linux.rst create mode 100644 doc/sphinx/_layout/nepi.resources.netns.rst create mode 100644 doc/sphinx/_layout/nepi.resources.ns3.classes.rst create mode 100644 doc/sphinx/_layout/nepi.resources.ns3.rst create mode 100644 doc/sphinx/_layout/nepi.resources.omf.rst create mode 100644 doc/sphinx/_layout/nepi.resources.planetlab.ns3.rst create mode 100644 doc/sphinx/_layout/nepi.resources.planetlab.openvswitch.rst create mode 100644 doc/sphinx/_layout/nepi.resources.planetlab.rst create mode 100644 doc/sphinx/_layout/nepi.resources.rst create mode 100644 doc/sphinx/_layout/nepi.rst create mode 100644 doc/sphinx/_layout/nepi.util.parsers.rst create mode 100644 doc/sphinx/_layout/nepi.util.rst create mode 100644 doc/sphinx/conf.py create mode 100644 doc/sphinx/index.rst diff --git a/doc/sphinx/Makefile b/doc/sphinx/Makefile new file mode 100644 index 00000000..99929ff3 --- /dev/null +++ b/doc/sphinx/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Nepi.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Nepi.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Nepi" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Nepi" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/sphinx/_build/doctrees/_layout/modules.doctree b/doc/sphinx/_build/doctrees/_layout/modules.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ec30cb7990d5858b8a0c9e043293b20687cb47e3 GIT binary patch literal 2721 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 bcTnjKZcYDo=|3=R1;{o1H>3Zht)>41B6%c0 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ccn.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.data.processing.ccn.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a5a881750c431e87f2d31aed91653c304dd10e25 GIT binary patch literal 23918 zcmd5^cbpr=*`T#&_n=BGUq!??*>c>5F89F5#5Xr@7 zN)kd%gA_<7jb0KGNsrNg^gy~NeO^eLg2{Vk(ucM)LgHkyuH&1IpJA5gyJ9L+ zaPuDTok<_?pJVX8nRHCkG_N!^;pR#O)8qYX(hD_BlV9V3O^?Ucr1x#ZPOdajtR>3l z&!ppXjExtK>^dWF@&#+!il8M!A>0BVm}!eu!8LMqtOjS&d(FYBdc6$Caec!#Gg&8t zslXS`q?ffG7ncF#i`Jx9wC;@wk|_!|SIU~gq5+pwhilNUyj z@uf2*eX&;>^L)!M`IhTsa^|?lw<`0k^+B4onF-VLjJ)abZASUF`e3#s1ZJY=mPFR% z+pW=KIWy}D1Ecx&YxE^X$#=(H*LPgs%y_;beExpwJCym3N!G)9STE~k zeXNi5>oH{(?!;pHLK(sp;T+tV&1du30zHm3wgPKxMYP6NWV6nS>P*^&4X^<=$OhR$ zwva8-m(4K(t8ztfwc>0sTg;ZQC2T2MTGIQn%qrxB>F`}g`5S9ff@fyoZ;bDjs_@;* ze2=8wFN_UAP?qVM-cvLXC!Sy(dQWgZnLbw2v=Qb`m?K8Pa*PpS7F}-y3`cTqcEl?( z%b6U>6pSgiA1d<|Nxd&uDx#mq zhe!3^Y{Bq6)8iwfdf%9lT_%+RFilumszkC0U9s*SiUXAIgTx z{IDb&9%Un=Y_Czaa+K{eT4MX1*uet(hu4}v&7AaOd{uikkC?9TBg_1#BwNN{|De*C zQ5s{otgFlX=pYsS~j4XL3OR%+SAkLaaFbG6w=xnxXbI?bp zEBu@?&mc&!l%^nM*mAuK&0OFrdr7_5aph(AH|ae&cfzn7UP^apnpT{un*#2bjlz(xPxon>HePZ_ zD)BWt_ zlN!uRn*p`d#5Y>$}+#IIt?#xoTkXU^y2DNg)vVt9Q_~gx=`#OJmG@1hF(X_Wp*jB9 z(inrqo6G!ju-L6>8m%~(`+QS#Utp`EuKbJB75=3%zolyHX0pYq*teGXZNT0d83t8q z?J|a~+nd_DgRN>ll;1gB;dhn!-BsJShPKU8eVTNg!c>gkldAB0%lymLG3T@78e~bd z@~?o+eM!B`oGc2xi}@1;{?(easIJhj)n&V)>Ew{7CWSd3_%6fmTPbW7UNH+D*Tx;f3}KUoRt!TZv6YWTtBFvm{CgnVQnz5vS|Ip z_;aZWf4NV9z5%J*hM||8Bans1MII6d}<-~nv#(lTw7To-l z)W2c=W0qjgFe&H#p%wlUQ2c2FieVAOf5uk*FWCS2bcO$-%zudt4KB}9q>U1SO;y^j z%KX>WaIU2VC2OP?=BSZgM2&QKjWi+(n^__)M2Ym9*(DM~G4xWI|F(t{CDPv|nZJoO zDSB8A9(}1r9yt({Esm8Nid#i*Z~B0BHdMX-)yH2b zVqTK-k5Q%aN2*l*#1RwkVFB^4b_I#m(# z=4o14bjU{bszL!Zg6O1%x_j&@3(+-C)7YwpQ4!tqG;O*fddNa=WZs5N$>91_Mf6d7 zf7BiZ0VRNlwO}xx+HXu%!~y~ukU){50%WiuNWz9~w(F=^DBTDJTP%{?7ZcjRqscw$kKw1h>6n5(Z|Qd;|5_Au!piXMXtwEHsm~h&(_NaTVI9KmZY}KYF6~x_h&`myWdxW| zjKaihqe<$M3XI}Gbf7BLWe@wyTiD-I+HWvg3`r_0$jq=p1%^W^NY3}9Dq@7X?G<&y zgk8gyGgLcbCCfs@3!iF6g zcv+gTuoz)arz&C<4LBki5GH+;8RE!@l2RLmSu508aTMXKR&ds`WP0+y`%DB+`NIeH z;%J0P%Dp&-h&6kVB#x!#eEJY92o+>A6@Q7Y`Qo^FnpQ9R;!PBx<7Y?64oE`&#R=5b zb_F0#goBed4oV#$-b^s(r7GeiGPy>YOm9`^9907;maxH1(R%R~8nSX!oQ#GgZ7aT5 zE2rTpWcbv1nl?-N#c2WD#`Hif8KI-CPW{E{MCGznMZA?j(}6ebl>s(Fpi~0l3>w~C zhR;O*_8usRv!t_U6R%Opi=+)qqr%`EYR|}ao7|kmi^_v@TktX@ullf!NfKEyl2b^) zY*ZVV)IP4XE0Lk{Am4%k0|QhC7D3q(DpGpP;B^f#5;m+Oa}}f)QFSmO**gU3D(qk+ z)C)Xshh7w^8&|qXCql^(Xlg?;Jn(>I_=H#r5r@iRJz;E7$)HIB)qul@+Xft=8k59# zO67YVeUYkhKKj+D23!Qj1vu8IMp=gcZG?JZh?=lrXAaf4hz3-Y0ZIlT;kYQ%t`k9FOid>6e4J&kR3qi16of+^fi6WyL#zldwUEh1nFh zpJHQU2H_p3n2`b5Y?GU0&@Lh3mrCMxzysdUqKj@p#bwm-a@mo7>Dofl82$h*-UZhK zX?!;kYbuTJq2@>$Ly*ms#>J4vD;i7VdnrO!&W?~BkR)lmirU(j#;f7rq>Y0rjn@zi zr14rZd7U&FN@L_)D2?EzO5^)z$jVXiel#p@Um8Ckr_Be+@Q3Q8@%jKRlE#pXxB+eT z()eMb0%`mRfqpdbrcG%?2vlkO7!7YOjW?oyo6>lbboS%K>l2a}Nh6p>()dYg|CDUE z$<2hyi=^?>EqHxK@~TQ>6t>Sw5;v2P&nYBeHj>8AQ~MW`b|o?-jbCiR;7ectX}pD? zZk14x%po1!)(|6M!#dLQ?b3@#8t;(o?oiL5iSDb>p0d( z<2PjZA12gCLezu}J99|mqcq?#Wq^`FNE*Kxv1%xd-vS#*AmWl}1ci zdj9e(oo}j4->2q$`Y1d)Y4E?e%@nBl5U3wC7N{Q*&*$oSk~lq2=i3*jA0fJvHV&#d z{g_}NPCp@YKb7Xvdo=T}=Ftsqbt$rb|E)O1lyu(yrH9 z5cvm)K)e1)Q2&xpjUMhn0sh?(En$NPGU@BmtwxUqwGMiSJ+FfvlXryA&}|s5)3Z+M z)}?flj)i*GjixsAtfwQ;vtB~%3lWFPqMtCfte#>1K+oVXA{fIFdN!ZQUn&=;v^ zgXmYIXK)c13vsN`vqdueiwSi}h?=lrXAV7EN&~i11}Hg(^la;hRUMwF)J38Mq+iy?J`SgK!Mj!q|c{6kT0CM~rIvPHo+kx2aSkI1f{7!Vf{T#nDF2SUY zgPP-aAsFQNIGNj3noDmt+pB73$KOzp*1=6p>u;oCD@Vm{Xc%Zet?w>p!5(CMSx4>j zxkLcBk^To6g;^xgP@l|G!~@BEIU(*DxYK4bM-0?tK19QtC-W8P-)1r&mY$9fue~HM zO6Fi1CG(ZkzPD_*$<2hyi<0?1EqLuKdEwuuO3e0?4E84r2Ph0+GfLqHQu{$lyAl>k z;Rm-ce+bMYg&#^#he@dP0_E2oOeAEy!y7^+Y>+_aSS3BF9V(8Hz8pygj#9Y7WL@%J zP2G-Gx=EM9GZsHcRe2^)6iNZzN?fYX!#N+zM?tw*fpPTr>z z)LSE{S;-s!(`^2a3ULNC%Tm43%OabZ#s`tc&upB=&mx{@*Yl(_K1%1?Pvhs{VocgN zsA)VyFi7L)k~u?~OYcDcjH`bcCOKZs(2G`x9EpFsaMbGjpac8OO}@}is$rcqAk z)GlPZO>QPsUX;_l7QB4P3k7<^=#?aw^<-;^@2DQ%buMAj-)1htf?t5$5x0 zG_{e>-w7Vb=Nk!eCPW-6i%o>FW%D`a3i3G|M%*sJ5&8U5;(M9O_j39o^ZC2buO^?v zMPR%e$C`Zp9vS{C2=%=oYQlz{Ir90HG~g;_fRaxrpI;rZnmeCgLr~X7Q1q)r>A(Af zz5L%TUe*-XAxy!8pZ5`~rnds`r)GI85Fu=)hV(!~KG0Z0K1i|o(CpaQ0YlP}>#41M z9k~JCP1-o9I`UzHfsTBHOny|Fq^zTOh5%Is1l&{s`4|mZIVx^MLr?nxa+92cA1A|~ zs1uM+25|CLAR;3^g@$_B_%!i=Y;mu{^bLiiuYBHL|pGokV#*|@a@uiGRq+zKc$yInH4gDl*sFo4ZSEbgNAyOnk& zEF>29v@m}!%tI``Oi*8uQ1T_2U=ktM-q#Q&VS@m2)>ow$^lnWsOngoHa6bV*pm2n# zI>~sDx;>Wom@lE3U zEtT)%^hHX>6X;hX8E_F8PvTf38BfXZf16Oh6QU+;*qK8zzDonXrwmXs2ua4%5vxX$ zA)cXj{2=ixVSQg>rH3_5I~gxdc=6!<<+$aHyJCV~Q;v@dcOst6I=Ohk&Brl~Jn;iK zmaxHzg$b2@lK5d`646f*&&inl2S%Tlk^2#m|FI-*2Tb6RTz~NIC)DMqfqy%rS_)?W z!SSNuv$*e)M^%T!&zk!4^Ctdu1~1ErUr2x2F!D>u|5rrr*8%^)G8hwoGkVPS0(E>* zc0`^dWxx2ptn7_9RS>^{+kwo#L=>CK{BNl_pFRe;v@zUfYJMLy|96cw|7D8W?`KEN z4(O8Rzd~*8YyKbL>ZFZ>s`-B;7-;^V$mE};Nty}G+zkJX0G6uy|Ahvx92I{>Ltp#q z|2H|QUL^{DuT%fm0=SLoZJS45`~$t}OM!n9DU<^LBKUs?9=2HuAS`Mr@H!1|UJ7WP z?Uw@cI_XDT!5av1hY%5e*(Z!GTM=Nopdx_7h}%v$ zq9WLt`0k?ejnfxd5$uY7H5CC|1jZY2tf>fgli}Z;Q1=K?6E^J3Q4uVo0SRS*l2xc8 zNJgw0Rs<=qfnY8ts68cA+R`*_wL4KP`6j(lR;>!MZprbzxZ&jDMm{ghyy2T(^?jq@ zeKRX-6yh0n^nH@NRIMQ-g{x-Nbb=*gG3}t-d{|gzXm)*s_2xFk-`w`EkTE0Iu=hG)NR};eA zOhNC3pdZlL@b|m}DSijdj-MTHCP6=#+S(WNL*VbEje{!ahY}0~{V+0lxHOqQx|Ofh zcc@$LCSb!CRrXhriIt<`2sHGzFZ)NzNq7_yUENvx``^(4+{W~dEy#;w(6wIsk0oZ% z{^Q8Tn}T4psr`tcs{O~)@a7tO0{XZ47~n+d`m1_0AY``1wWTV%UUZYES- zr2Qwi;I&rrY8k~-B&So!=4lEiu!sr(o!U=V+Lb_20r1uqgz$1)k}7~R2dCR7G$R z80XopRZ#_OP!(NFP;Zw|>6z+d z5~_)i^JiB=)e0wk@xG=AqIMPwj*+5vc3N43D1!YqlkBz-5^ssmbI3{d3 z%R(`vqG`IZcTv&wP8sa~SMF?-7kh>RzDWk$4t&H_P--eHxZP3}aS8RkRQ9E^D%cK< z_8k+K)rLV_jx)6BPK*7!#Jdooow0Y9csD-AXxpg8)h9mhA?O2B6>$Y|c(3F@f0jFm zc89E9HBVfL@d+Dbm2JDkRkiGbox4ICS7X4chLG3DSY1oDuamazzzzsWwK+Fc5$~fe z@0VRDkq11o)oSkp)Yi1x`ye&v)4R^GQ&F@R7xpu15n7aa9}3F6a7NM-FB3}|djZb( zh2eO3{AdbseW#|a(FejE60!fDxPjdIaHpo}eZr*QK|S#iI{8tYT;xqnjJbtOb(AMQ z)~RWu;zl$sp0(p5;oU^7A4ls}HA7{GPf&+XqC(8DM?b(NOrN5TB#&eO6BH0VzJ;sc9$9(+5&t}F9 z&&-rWLEH-xJ22lb9y~JQyKcc7woHF~*cJH^Y=tu-zKkCIzA&;TZMgWAPEDK92a9GA zo|?jRvZg2QBkV!!vW9I`C$QtJC%#H&2YeS6s}#Qmz;0|cHzn@J=YfLZl+hA@le2@u2H67t~U$f>+rWjUy#X}o^Lrc6T~;DV~iPvYPW~c zty>=m_{mKq#Utp)4qc<~XbRzqjOk=u+Q~##%woaFn&L5> z?#`KGrM&niSzKgJjG34*Qw7swrs<1sb!yrseJ8i%7fXIK{Ko;*18P}cJb^C**bvhx zO=Kpq?8KAuqAsNWGlw(S6Hk%Vft;I#vIU*LEjtfxFoc6$i9BDJ#)S9|_1zkm4UgV& z@iV?TQ7jm~DZUG%eMPglVvoJ{&57^f>tb`#@-h4Uk{1N~X&J?ytm}+hdGQQE(lyWe zne~=u`K}PpN<-O#Yplzd6NXj5mSe)iww>bpGFMydnbo0}5KF>8uw& zBrxfC(KAaqH#0d=5YN%+MdoDD^~{Xr_@;1-f+wD*^GgstuQW!Ra0XHN5n;}kdkrBY ztP?+`&VyJE%0&K&v{-Y+#7_~D?vg*g;z02;e2xWBSVTXUNS32sWbq4h>!%?rJS#7L ziSG+DImx#JZW-6hB!8#ZhhE>8K(btre_%=IHhv*?Y8KcLqlZ_4qF z$qcjdtYGDtFaC(rT?N<4i$CGxjaB9lt}NhR}OtPtn<>X}CY>qCUgec~*4eoQ|Ei^lrzoajjwHGuM=psgJ=fn5qY=6XLK|~F) m2(~w7sURA9e^pjJG0=rFWv~nRnf68V#6rSb)P=Hc_*jI zx3LT?t$_ra`@Zj+a^LrT-}imre@6Jc)yjuxnjcr1o%zmpzH{uI!+sF?i4mb*lu>}X zY#%!)O__!k)@V4TT~#Pa)^!*R7$A~lQB~o zy$))f`5Sj>0w(=LDU`<3QKEdLiUZ{U{YWwUHcdJ(%@Px}qR7a|pr;K}hNc=rFlN&b zfu=nv?XB`rnCj(F+st8_kHPr%4EFIN%vt<3i@&yozt+dUKY^mpMHncQG~?1`gM@1I zEwD1(YhjHJq;&5ploVUZ(I12YjK<6+M6-MtM)Tk2mToK*3UwZJu+BmuSzTcq>AJ;I z4HEO!bg<_NW%gR>ehzq+cfk$1s58uyVq-TH3r7AD71a^l)A}utAq1e|E zUCoF2j7#^e4iaO839(G~TUeu7N{dx~@X~6j^I3j?&+&PFIgDfu=r})|(*3LaN|#^d z@*^%k>hfc5!WSCDJdgc=!O&;0Ysz%u(($f2w?+?4=|NR~klWa`q{)&dx1~Ip(y1yx z2!$<3{E)@+;2l`#TE36*V=g^}k1>mCq>t*lDz~{`pVAFBciTL-Y-^r}@>zbemnzS4 zeAo`Zd5)Xj9?nnvpNkvMt2pE)?$3^P=xdy6rqY#aX)IQl_zxZMywD zJr!XzNAGUHM4nGegsAChE_qdc8^0Z)*kRoOW5em`H(j`J;er*>7@u*oVq&gFmQu4% zVBR1-HTpYLLqT>``EP-e6S2;5;DMUnc{^tqLfrWf5zvabe&xSLFC^+ z+Rlp1l#EqUQoUHQT{>HZQM;Z(q?M)li|wvzZ*MGIib^OL>Si1c2lznzeDeTd!on{nzeM?Qxap?}&yJO{LZ{O+C z8tfl1@BQ^$m!1bDUzluVYI?p)=PW>&=lRiVDT9hO94Lw) zU$ZZ43_)c(7ELd5>BUg#2kQZNNlGt;JwgUTp>I6HR2z+^m$~$EC~7oD$hM|eY+D&E zmE9RZ`BoMtsLS-qh+dV_tE({Gr^2&qDim^A(`y<-uus{eAn*c=Q3fb|+s&_aU_!Ng zugNrei3;g;Fw2dJudUZj6oq@-=Ww?HLivYoItdVUljy%mO0(%YaEFoW8# zPE2pN2s3WI5YJ*r?`RCegcqPTLiSFacREn!EbJS+t1$wV97Mjf-|g_@4$Prak@8Ub zQ6Oa7>pgNNgAf(H2liNqI%JwFj6>!ly%$CTY$k1bp96ca(?na>)etpDH1z%rn2!<@ zC+1>4KLDc^h;QgFsMuRWCLOP91x_Dq48c^8bYgE)Qkp*GKqZKLAzM*y_Tk15Os+5` zEnsaFvJQR3ff>uYos701_wmLEjQWvm zi8g&Aua$4SvqB3KDf*-XGkzGcWe+<{gdPh5h1uEjsdbn)N^~|GZL8{@jxAT8-hf>w z&(dd{Jg-<|5=36N6Vhibecd?H=m}|1Nfv7QoCDLA6P+}(%O%hF^BXYUJNj(bEz=hq zn6whzrm`2JFlpzN zx5dEEU|0n7bC?Vwe|w>Ru>rHaHp39JUiVgn;amSteQ`HLC36 z2BoDwpkJ@UxMC}t&%d#QGh=6S{QcHRnlLjszwmx)TNK_MYxt(p&3`@8<{jG-rGt zKbgSvjt{rqn)-W6|KOMNtF7mM=ANz7{L6;V=We0YAKaS$<jv4(H9?ao!Bv?s5paAd*zjJ6T0&9E5S`nSL{`=X$!Qs$bvk zqK((+;++Yzm@tA7Okf0a00WpaikJ~2MpS;kPu1&*8~J>G;h&xD?s`?AckrbBam5EcXFs8Bh+SFlAnfYAuX%rT9#CW64Khyd2+VVyZv3K4~;3V|PDNx=GP zGi8gCj~0!F4b$cZD^z~j_m$@>Q3#ZU3J%`gV-C>#ICcPsL~v+E_RD@bU~Z-f8m9>w zZ%xoRP0)BF&WFiCGu0O5!{v}1k|}eoc4533v?JuO9F`;I_T_Zaq>m@g9~qj1CF!^} z3J;FT!_nPo7Kjpgm4aikF>H+BVHtA>t(nC2O{QV?*DZ<$q-C$!pWNS^JJ&FbN$J}0{U=KN6c{l#+>0|i^m0cBMvcCghPND#rXX3A0u zonoj&0NWyXc*Y#G!#c?Yusv@Mlw2zaL;#t*IastxdywWen>P=lDL5_<$IHVkvro(K z$iuiCutIZ<>v#etcK4ctjU@(?vR59JhZ8d0(NT_aMGAIiV>mH_M`YxtRj!N zo8=a{)$C&}aI)MM!6P$rdtPSpGMksj<>iiiC?|IJ$^^ipy6s;mW>pHNR%!H<`4~=( z;L#bmNfLk)!=e=yCC%(<5j-X%HuW$eOHvTd zj^MEr1gZ)bw5r16WLlo4y_M|d<2$q_ZZ>tDBd5AGoI4-G6C!vbK__izGxP@fT@mbF z6#bJr?7(>$t_;blS*b9>v^-Lfvrm>I?CfB}*{5XK+w&uMDtY@*s?7y5EqAqt;=&Gy zNhq3@OgZ(C)L%3o!_y+jQJl!s`5dQ`UTzbXZENyyJX_4B;NolyPmkb|M(lRU&F0W) zRJ?4zbUIv0$;qOSr(AeOhH^5SPf~P8-W(8~LPrF7C}hljVis4xWx4EX%5O$bL-wIe ziD@XXcrJR9xd@AryeLLcYV#s@#nR;`z*16&EM-l$O70|;+{p$%&7Erdr9h$MRnmSr zy;80$LPNIPDmiRonXr{J^0M5ShG8tAu}n6dalC}2RptuE)h0b+Ez`ZU_Kke zRS`UIMJ{TzVlpk2+$e z#P+oxFV4nrbp$V=N*1?a9BRtIO9|l1mIL^5IkiNjUojuUD z2~-MRosHp|2wu||+KAo;M%Ez=uO*1DTMpvumzdC|o)o+x8^g5`ypg7qmRBR|N%xx; z>Q2jRs9Slnoa&HHTJC-!} zPC3;Qg?G)z@a_oS)39|t+mhFXMG-D6OTOpMrQn8a3^zvb-o_XuH&0VlqNngavi|;z zxkk*^(Oe@{&4mwim7(@^^1%hwr7k?%@hXK`6y+4$l#Su$2tK5ZZHwT;8FK(dnM##8 zxYrRgwCdp_WqC{Q+hOoKFsQIy4O-E~TiI?!TJ5?2;h zgksh#=u*_^l$T~Gvkyhtv1J^}w7ik#`{Ui!%kij{O~EbM7;cT=6HQk?nM@*l${cNY zI_^5&9{9A?)_A7n&7}7;NgiFId;2_mc0PvBMezB?Jl(4Es9)QIFX+pW_ISe=d3h~1 z_q=G57nl^>mW|=|2)@+N?Q~S8L=3)66ZVybso1JaU+oSC3hv0paAyQxqvSr_ zFpRToJ8cWsnoB#Lk2QXaODkVfN;;&jCQUPuF8Qu2N=n%JW{O{;;p;LjZt5&XCd6}KKg$;jFPxkRTSyBdtUCCIzm*Zog3 zlG=uQBKR52?~cVh;5^uo_8fcXjz>^%h2dCjD=&<@&S2N9(#HWqn**P zx5qH%V?3zGFd|&TL-p(OgH389Q`pA>{aPTmhFV6)-YK_5IIx_(L2a)gk3-sAinR^5 z%vDK$r^OML8BHt>7>1GLG#MRR&gfcgv~38k({|Uh&JAsL$x5f)gIVT~#4aJHDoI8U zUC!uXEl)`v57!otU~NaXStR{Uiy|z_8?rGT#bQUd#3&i2B)dblX zr`Y5v+GOsKPSmI4+;Mq4jUEiGo-*++^ra@q^tSxScC z#oC9bv*JtIFp{YzYtRNUvBsq=mTwc&t~80`8T4os#8Dt9L>!l~MysiDTZBc{@&8L4 zoG8Q{3 zwGC*iB1|7%3)N!ufj*(RBO7C#Re@H;YrByhr>5(clJpLz&?*V^LnYGm5RnF_tAs)} zYbm{|VX(N_=Gz)79R;c(E87Wmc=j^H84a3AOE$0xhZb6JdO ze7Z_#+m12t%5HecNk-Ggb7;WSqAH)OgEh~#uhO=wi5&u@OVY*J7@x-?`?Uxc%>>7# z4c0!u&z5BE=kw#scsqH?J^j|v1nu~)6kKBP7bFbc%oc8P1g!%)A{|y}c|qC7nm~ME zk6}!kqs`-CI+es1v12dpF${AMMVV+ez^nP@OX%jhV6Im5-9lqjfG_Paj6A-K9yQzs{t z@4LZ-BUE|9$I2vaQ%>T$Nn(gg5g$Xpr^hh%n`3oRCrQ zM}Rl--BIO}#RkOplEOYZdz-`e(f^~aOXiJFL|U%?u9klWcX=_Dhae z_7mYxY2mRM3q9H~4ipNjhM#8HLuuNG0BG_HO4RDEr38M4j1JaCeSF&qC)xN}x?C@2 z9Yxu%!XOFu=X4bNOTJfjD)@O;$#Y&(g}qMTC?D|)+EB^$tvv-%vmBSsWKht@4ERM( zo{b8fTC*Co(x?#BDX_P3&<+ybUc8-^X~*k<2yMSGTXXSCe0!akt^0u}IGz&dS#E$| z=KC8cdO=v^FB6iee1&xm>s?@~2z&6WEIdZbp)HZ`&=$L94DY0n^o6QCK80VS|5J%7 zT0~#hnjEivlJOfPHpD~51E+%Dr0cZ>+X<|qOS#TL{1%TLa_mB#_QYrL+ayLS&MFpW z99v2J4uyTt9P3O{{4NRhnHQcjK84?-{|Az9dhq*H0=JlJD?%wTt7tvet&+kYaP)^N z!V_rGT>Vf3=e%k~@ke}jB&b=a3K05A1b7$6Z-mmPSv!7AMmHt3V`gS%qCTgj?{V$0 z#oo!fs0Wky6OvjN%z4V1El8&#U8f=y-c7gHxV~4xpVGg_bVjdh3EtCV7*$>xV^o0) zt#JK}2KPEP{+#|9v;9*0wEu!(AFY?Ya0Qp8!i=M2p-}{W$=;48^TCTFz+X{?HV@;K z;&_2T{g}uZ$?nvS9dkiBR;~!Z3kK7P+_Y!8m7REnO9&C&7&n&i`KFY!SDUxJ> z4ol2FC#d=Me)?udf34H@WkSEaM;@VDl<8_>_AhMquPw9uImo4QYqeqPZ*8{zPWGo) zG<3K;O%CaInj_^dIV_btOl}O#4ISUL>8|1*4B(%nc&nTw=N@PoB#)Ahxa5|^Cv&L5 bk^%mUdH3IxD0DF9*a7~B^*zXa+QfeY|H@<8 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a07ade50823c2afb51c42c6a0c61a71127c7b427 GIT binary patch literal 3634 zcmZ`+_kY{g5vOEJA}NuwWy^If%XSmHrqW7upJE_cI#fqR-(jY&li+7 zGz(*fwQXi}2*&c@bQsFa7$usCK}| z3p*@9$6UH6-^*a6XMfzK8ZWX0c7{SC%{7Lh*w+PJ#fSN{OZTb`5@Cc1u}t@#Tc!Dw z7Ha&!rPZ(V8NQz%ofF&$@@_!juIJ^>EUy$bS9-o^wY}2L$Pl{kF*IsDhEP0!la3OqY&qp6^mn3 z)L`2vuk@3BwBHlp0twG4w-&TdwS?I|~M>1R?ScjeMFly2*>sA#<-CQKcT^K`Ylt4{S zaA~pTEbcB8ws~3zm|=A51$v^hxNq=3?4q4{k)+!$(337>ps?4bn%oQYt%5UQ?_YjI5)(tQ=oPrxKUc7kGYHN&7yIGAf7b&LH z>hqfSNl&EhZDJx`%fyq5Q8jNZo+ac1^7c2dhQ|r+)H%Ju}3_T;`Xej3>u?4`S$?SZ9 zaif^jtw?oHQR+ZtW4B~O^O-5#4n>8n-mttQrB&FaS31oo^!k>Xp5@ZBVfVJpl)e2N zm(Ii90rTEp7hHNSlzd^b&8BJ1rF9DsCi*Kd8^_OcU}^*5=CXXgOE0jn;z$`(^g;)U zBFMMliyA{v*@{Kei(PsNRQkbs0A8BX%V3v~fl%lh&oI?Sqv_=?y#k6FjS;e~>6Ke1 ze@kWSKPcbA!UT1hUKP=+Q+iDerutNPcH4wPE@^sgV+i&rySoD~z!+tK(zi|gItM0H z%lDd0qnD_VUJoShyF~&9pR49Ga z^d<+Y+9(lwe$=tojHWj`P%)7W(MR(Z7_mcSh29F4kjZw!+UWUFfb=#PMoDjnQosyq z!#Xj&!y?SM^+G&{A-%IP3=>{}+6dXZMBe2zw<%I61R)B^Dh-3b+YGRUOkb*;eZLyaMr43bXlZAePfhaIQ{kuPK`%FRB~7=r3D zQ_=#~Mj`9aM;(~9yxVDKi{=^Z#33_CAA@3y@%*t9*97!&*o|FbtPoA2bMijX7=ckg zk}c7uPv*7qjdxCHVIoDJa$wpIBevvWhl$W*L7*_ZUOv4Bvqp)|Mx$+3-P5t<>ND%G z1LZmTtdr*zYfOU3>vlr=oTaZDM;bjL4Jye(O`msQ%5tKUW_FO|8Gm6N#(PV^cHI(v z(SfR!=oXcI$$`lM;_1sUl9<-~Y5EG3^VhAOzv@6$$gL%!uR$rZoY$gFUx!IA5SleZ zE5VGHZ#YmAffp-mi7tH;3Q#hv=`D-EaQarG2-WR6qHn_poINvtn!W>L{bTvNd=@6# zXbg6Z?S+{6hQ7B3r8Y`b%#!_m2dbF>HYxdm0~5N#l<_Eu>_Pd%b(pZF-ssOC!Qs3= zmzS3p;uXUqne}IY=jt)Wx=uf~Ls1&m^|)yBP_((BpTN#Al5P4a9Nf;vKok6o-w9Pa zue?nLeh$MTpkF{Wi2SXE`sF&z^x6zV%zE8h7KVHMru&rxm7LQ|s+xZ7!oEzjLTXgm zHwa2geL%ligK@={H-7)t4$h37jq&$8Cuzd;-~jJ^b^N|j=pEF5Na>F?E(TAx-b5|a zpXOHS&nf+7%j)BH-;MSR=&yF+{Vm(U$6We57xqen5urO#ux8KX-hsTizW5$~icfLm zd-?tZrnY@w_14rsQu-%9#ILfR|CM{TPV)~EKAXFRQh#u3`nOB}fl({KK+}Iy`d`vq F_&=!3HroII literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.execution.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.execution.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d18e0a5682782079b34a3cb77112af5d74a21f30 GIT binary patch literal 620283 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 bbYV>|W+Mmnq72jJ4;Kz5ytTcUu}%CR_25L1 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4acbd6abbc037eceeb6d0e14058ea5e7f5085950 GIT binary patch literal 3838 zcmaJ^_kSE$5kJY6bUHO#wj5*0g~Z0EfOG~2Y=RTIfgD*%JV7BW%e&pVdk^it-Ffe= zbpn<|fQ3Zwz4u;1@4ffld+&dO`MkY7wM71L?`CJd^PTUMy|vd5Vm~z^)Uz@UP*?0@ zgwj-~XL^ZxGulywLCGRCiwSDlnNeSLZmd))MRAaZc*KvTL1{GgJ99&&Qc0(cg!%KV zg_;JOxqYQlNn#>q73w%uKI$XI-&A%|*sarsHo~Mv#L^3}scA5y3XCR9Y4jr0I`=f> z(lCtrsZuD7*YQLn4paj4W5w*-H0r=OOHJI2Vv1pNuKsn8_vh5q9Askt+yQmMw{2x}}9lGPL@v94JZwIKFuI^jaLYhK6} z(^mXiyyHw?6mcq_ZNTlg{FO<8gp(}YWpK$4})vc5m zVM46X-KLjlCZpLZKX55+)c7Rd&!_l7ehB*VSLp;llF{9({BoCH;qs#{Kj!k|Zpx?Y zy}XEekF7z^VcS&bF#*e#nA3ne=p1v-gGgWT$y(Xh;ZN9cWZrIQs_vMrPR3}NEXLr9%ev9nZyxpIl zyq${&Tv(z9X7nJ7-nzRcN57Q@KaP?(l|h9bJiSC`GkQojts*>>yC(Edo8ZF=Aaos! znb3i}(PBnV>SiwZ6bzoRn6W?6Zoew4oi#PRJ$+CzbZgFAPr+Mi%Y$iy*~tY%Mlq?Iv5HX9k^>`a z+c6*UPs`}(P*&LNjP_?_bOCnh#i$X7Ue{97vP;i|-J5o6{`QJXtFU*AdFQWZx%6xp z^o7ZHv!>^`^jr%NhPz8VUmnkMV0;bX`nrF z7rXQl80iM<0C;IeFN0k|21224Ji}BAji#5o^a?0zG)BmlrdMv*Q%#khGC}1=7N)2x z^s1O%ozZKmFy5uYv%4`Aa$eJG>pieX+3O?l0!&Z_D1AFrUgyBDYWiM-Y4lPR((7T8 z8}m)O%obfhlPLYom}w^ic;U zEbn$6+M;;|qa0?k%Fqt`a;;Mi?4!f}}j1{6ubwS=I>V44f$FeC}^vR-DzVXfr zEljNFQw~h{Va(<|jF<>L76c0OTkF#+aL_0btu@+u)jge9u0FF0J5Zjd&pJh3iN-XD zy>=AR=PZ5gB-ZE&X;4WPYWlnbkNB^)ifZ))9Rh`rzEznbY(g80en+-{l8ktcAv4+t^-6m~ZHN zD=^qXiHcdWzwf|kE`W7Pe&E2cj+inYrLjGKf4B<6w$y9=`6D=7^yk9D!fdi=cr5e& z4Dfs{!9>^S$95=6!`dDfEgp&%H}n(O8OE|jKZU8yY;0+QpYhvZ)Xpn!oq?Z2uL$TD zFdD@E#zOsa6(&1vh9Ty??kxzzy>8R}%7KxB(_E^We(l1(T(m-JRQXpFN=tn}zgdAH z#TM3{e`^P4&d%ES`<;_EU}Eb4?|e7?zFz8_|9{Bnk5#^hpW@Nh!?H6~EA*%7CHiwl zf7!4Sx!r^P9RvESU4(zjck?lq{>~$NLqea>Q5>w;bG~!PudgsZ&IRAg_opzv=?k&5 wrv8!9KlvekrS-c9dd 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.doctree new file mode 100644 index 0000000000000000000000000000000000000000..26c8ded5c0a797c4b4db441d6aab48476724e75c GIT binary patch literal 433963 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%0AHSvT@5DA|GtdNP^Y;|_LBrE? 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

UDt2Lyd3Hc}n+`Kj>- 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 SY#@v(Zp#yi*Tq%t)c*rig)CJ7 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.ccn.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.ccn.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a3194bd8a86d53b94ab5a5a69c155db7e598352d GIT binary patch literal 30797 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 S|2s$}E%6ljdzy4c$NvFr=|MIC literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.linux.ns3.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f82425ee20a3cbd022e38a0ba0bbbcd24a4239a5 GIT binary patch literal 127381 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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.classes.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.classes.doctree new file mode 100644 index 0000000000000000000000000000000000000000..10cd63b1e2aa45bb37d16e436ce524674c5d193a GIT binary patch literal 490090 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

E-}oqzf#e;S=a4|SxU5ou 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 h7#L*CDO&Nw_J9h5IdF?j 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%0D?Z>gthq?RvD|SXf>@4b(Q7d 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

xuQm`eJ>tf!IKd7Nf<6VneZ!*hq{KW5mW{W3h?Y zL~JTH6=TI%v68Iw{}EDGen2$L}a+VpKn_DOl&W<7dwa@#ExP|F-c4k zlf`6FC+fsbVkfb)*jdzzda;YxMeHhe6}ySu#O`8uv4_}0>>2084l&zU_*^uI2C-M& zhzNX9H_=SJFGN;k#S}3`G>S&iB$`A{(+^=(_UnEN2MtS!dIeAw2Ah*6{4%F7-%LNrH^`_ppVuqL@W{R0&mY5}Gi`imtvA5Vq>?8IS`-(YYj@VD^C-xWnivz>~ z;y`hrI7l2M4i*QCL&_0R>i}cmJ8`HuR2(J_6Ni`WVzn!6YJ4xcM3*>193hSrM~b7w zQQ~NEv^Yi_BaSUMeZ8Gh)5s6vIB}dfUK}q@5GRNe#fjo1agsP$oGeZer-)OTwCE^lsskl^JCN2|~*R2^{*U@;Js+cBz5m$&S#FgSo zah14ATrI8^*NAJxwc=WFow!b1Uk;AxC$3{mTfd4M#0}!ca)XrXR#Wyjag(@7++4PO zcO`1-{4Q>(n^!5|aJvruL)uI##t(wrv4Onh&#lc;!bgwxJ%qE?iTlm zd&IrsUU8qePuwr=7Y~RB#DnF!(x3F3M*k8ImE+?};7$3z#lzxZ@klu>M$&GI{v#e0 zkBY~{W8!h~xOhT5A)XXZil@X=;%V`;ct$)Uo~>IevG=|G7Sry(;yLl0cwRg&UJx&c z7sZR6b^RMfb8C~#wHN-|LuPtpGQlq=7ITeAmuh5>9+}Lr17*)1namv7t4Ag?v~GaR z&Q$4^1RN>yZMl)z*5>x?NSW)%7e|7| z$fkVb$YO_RZl5)>p*1@@-&x{wyP{R!b(F=D><2sjO4(^hvSfe$r6I}z_^ZZS;mR6f z9Z0PGn>ssCrzi*Y$Yl1Y>&I_^W9dTo~qqUM)43T5~mW5#`fG ziE}X&Y=I*aF5t+;dt@>#aB&NIqXph=fn!?ek3MW%E`bNi152`H@@^sB7LsfszZMee zY*7?iJm5=3jE2d%S*04ebP9~i^vGlmJy0%7YC|lw77sgEcTUN6PHE9YYdMx(-j=N^ zPqGDlt=X**$4;(@j(9(-Sjv^~*J4@CwvWShWwxR_WECPAYLW0ea+AF8$jMuYMfqJ7h_IE zf)UxKCIrP|jc%?+uBULXPuv@XaDz{vE9&~`%5t;^dqdQ$>)+nlHYF!>O>!el-b~%# z=Jv+c&ZeAbZfeT4%P~DNnIqW8oQ~z=lH8bahqJDjZ*QF~H$m09-qTw1Q{<*>M$I%e z>)d(BxmVW@A+tGGlw%oNHtUhe)bg%Vd7~pt_!`$ElQ~R|hllI>YUmSae~{)gwYfD{ zl$*2ZE#L)I$=3C6%g$=bb(DnMvPUMf^?(2U_n)2?{ltHJa0KPNxw#d6zIDjw5dp}Z zn-ha0#2p248_dQ}%-q}-e~mM9bC5GCYJpl$&Fu(edkchLNSI_7M{)<0<;(=+z;JM9 z=8kdDd^6L9G6{`xX5xzwj@`*>V%8DfP8ME^hX=^%Rwv}`%;NR7xS4_pZrvpgyWAE3 z%I}8j^a&ap&{F>`Qn?#^|7T7|$=&hS?WQN@b$VhC8rEI0C&4#Z@G)OUcak!_-6Z$2 z9R(-EbW}EutgoY7q*H81mH$$G1gb{WjZLJMv(#EVv|z2`YcNhVw>RZx)ySzTN=;)E z!Zu;L*0QY|un~5Un(~bs%VwZe>djVU3mz!-p3WxHMUXvYD@xb(EjG7LYt6|vD0TU- zgu4zHss_ujiUv+yrX<@DPITz#;f!Fⅅ>3 zoo{&!8Om@uq`7@a;#?Reb_c7X$EwyP73%e-T(Pl6mQ<&AlIn~ks&&0lOV0E66K1NL=mCA@)&ePAJr+x;&Z01&(vnD zY>q>hhx_CB^8Jx*Z_lgOQ`E>4REL~Mz$bYf($@@uAEoe0mc2u)Z7^60Rt&^0x|w>9!iMf5B-bGB_J=4!ap zuOrGkVUTM^p5uAo+-f{7NKDY|9E z#;y%D7B$irAXi^I@;Z<7_0^ER0hOWyrZrR}Z&YA!BG{WPSVr|+qgMJ`(%5Hi3)0wJ zxYc?b@{ntkwU(E083b_+_MVEt z-fO{{rsRDJ?)|j&fVE}d0)v6uqTuB^!xD@|SB-p7x%eTr^>C;yJ04WFQP-PGwMV?( ze-u^fdgo?!$hzL5)Yd8=!#~C*Ug3ECc+?8EBiG*4+&-;gmds79kxwX~PZH=;E>M;5 zJxw6}WNs?Nx~~6>=G;sun0y9;(O2fCHsu>zxau6hKaeEU^(vN{DwYiDGrBe+`cpiiD zxd0%}SPZ3-Ud0w7ws7RFpfgr{@au2dEU>7eWA-CbJ!)Mt-OOenfyDTY&sV zDBg=z96e+-bC=P3Md#7(nfqSKpI{qG_CCQwCVK;{dHJcw?z6P)+!crXoVA#E^vh%n zV)=#Y@Gr^gE02{^MnMJd&M7T=etymJ-+1NmBA5#3%WuJlV+suiSGX8AdcuDP8+O8b zX*(ay%*uB8J=X)?WR*W4$1I;)xc%S+3B8DrKf<;X*b>8p4m$EDRAl7o-!WVHLjH_r z%xed9%pR?i@n6#C+P}i?oRw>P4%{0C^kpFyEx_HdPp|Jx&z$wf^e_8*1l$lT&`SKMv6lE^m=6Z2s)-M^>ZB5=Y{=ad$`Y#u;%HHqw;1@k}_ z<~q40_4>Gl%VI1_6g)YoXC~9a)i6GV)qF6m=+*8#L^-cTS-*7T8qdD*aHwAHf?Z(E z)#9va=VOCvO*?;~NB0diTE1hDlN>;0dS*^}T&hV1M zQ7t~FgpXihgm0MHoN}ZZW^2&qnyyXi2e6np-{R(y%mO$7an_>q!?oDTs8B0Wam2|8 z*ADVZF>QPrvkvX98?qatG3&8#T8&wsrKvGnn4pmF=(fZ(L1H#YkeJaVw_zeVM`AW& z;qFSz7>pQ73_gV=W@B2>60-?WZfa4M*-$kvqA&^ra>0P=D9l*4rxa#04CJQD6=s|o z;o}K#Laf4Uu1!#3@GgRC-d;|*(c9i+HEcQ~vEK8eHT$_{^U`a18jclbU)JjwkapWZzcZaBCfjKbXr?uP)i4(^B2{9&$nwRSk1 zM&{Pwj^Uw$I~<76+XYrSxF11QM}}D)#Yavr%cD^(KDfh2uyBm+ZC`LdR`vLCw0XR1 zlffNW(g*hw*vg5aR-&e{6WmV<@=7s!eZl=?+C3#?Hzv5B%ED=b`)MrA;Eu29@%zo) zkM0u@-A_-5?q`tOnTgz-=zbOp{~tv6voU5E-SH_L-Or&R9o^3*(DN+N`o*H7JDsOS z7q|tZniJm7XIm<~Uw~mevGVYKp&H*85!}VG;r$YAg5f<5yu1{+6XW}3gssavmP(h0~ z9N}+3;ci6u8v$EK_?u|{X4kxm@VC&&+#2CAKy-wM0}+331uGrlZzHSQ!>sP$Bd43? zov0Qc;o&1#xXX68FT&rgdi);Ryw|nK2oEgjBm8}A<^E7BQ8U?z@DBuer5L`9@HzAU z=9>P41n^J@K*F8XhvNXqNARyaf{wql>b@^XJ_@)0ZEmeThQA&%HxU>0F73(3X>mslaKaKFsb6z=jr6Xa)PucE>Q>Bj@K z{1s2j-J@aeGU}`3{91X=I+{9{QD3i!?;9Rp{7Q=1`*PoDm3$r5?cibJVK95sV-|Ua z_7;h~ok+~dQr={< z`sSCk{FUb(@BX9;Iq+Z54bE-NuUXR(uM|OEeuFldqj=Wjx5^dY5zzM*kckigszQmr zkNE=&{%8xv{3?Xc=lVuw6ffrv=1-M^p|B+cEtUy82m$E|5{*%0RSro`n>Z$7R>Z=HfPJicQ&MZ zutJ3cttTt#>xI2~;YvhrYuJAivQL`!2^0j7diCvPMzOvL*{>I`Ui7D(0oIQ31nk?S z%YXB+hE)dID)zdfPJ9Pd3~sOmXKy~vqu|X;Tk~041|Bd3;NgT&Z~Dy7S__0~*+Cax z5-f7~FC;K&|E!@=c)b185nY}mQvC0s4M3)s@V3xI3D zwv)jpT>xyc7ynv#-H$rQJAP?%t2N<9=a%1EK%j5)jiOW6woYxKlT=7qhfm$9w=SRX z9v^6MR@r-e>-CDe$A{j-lw2RiIV4iv8xvoAL?+N*oM^@%-Q8Ya%d+GEpR@%Q(}lHO*C^qjTF zI2NvI?cqQF8jrr@`U9WB>yHUEq}Lyt6X+HeX#L`4Qg`PB4CI12x3l!vl8vdQ$5t3$ zXH~QG*jf#+iNv=}ueb|*+iD|Rdc@+FwSdlDQcl=1*Y~y~1D(=tPXs%79x^9WDrmuh zL1#E=?T)PH%+@r5G6`*RHX2)UvT{cq!R%zgnE3{fDvi|%(atPbA1Y|!h7+P)P`Dcj z(XK$P6QbQ{es|Zrie7ur$lRL{VSwm_2rfiy+!MTXLexNBdxd#r`N-*KIR(|?6C!vC z78-4T`x2ri)#o|doa)-7Tmp-Yv55)MG`1o_twc>`Cn0JM@=7s&&Hkv`C^fsJEd($< z1R!CTv^5TZY{S3uE3C1*Vz~V;+u`kZ&E{wxe=T4(N0)UrM>}XyZ;lp-T3XaGUzddu zvnN_akFu9QJDAisuR|%t(ev$zx)3|C1bKu7SwFw$jNq;&2nE&DNiB|KBPz8x3KRH6H?@fVl{UQD11^h+W=4SpklwVG#{*yd{^be8Xuf_Yrx&>sWHGr!5ulFy{V8JtOL4GqL<~wfX={Vb#XH`SzY)c1U&WM2^&ruxD zCG_(wbi)yp6i1!fozH?7*n%zWUWV}L zP+rD@mxl^QA$B$>uc!v`m8_&UD6gX7tF2-G2IVzr+NWzl09ntq)*X6-@;c>->uKi( zYsYv3_HDl7-=MsaRc^9X?5?8DI&ZER+$|QI-JrZx!MlyNZnw4!JYWdGb2cdNV68ht zwQR42^YOb-xEuNS-JqcJ@q1|gUe~Q!^C_a#yKV`@SglY zjhPRL_9Khd#A~py^EPUW@?%!~BvjFk`|$eUQxaQ9 zoCuI+d(z#JJO@jK&l8pkUy#k0iENyu!dEO@)l$K~Bl$J@kIMyo3NIJFp&`9o_?AGw zvq0VDg7@oWYCeKgFne~E3*WO5wOsfCW9ggQ5M%zOe|m8j}1$p2U{(>r*QZZU^bo*pRNjg+TnZ!hKP)tl$(u6Y%r`q0Q+m-1kQ z=#&SZL)_~NIy&X)M>_q(bO!K|)5o#~)#6hgI0qI6qA2^?m+}ni&8q@~X>%UeCS?#< zZ0Jl(dFEv+^MzW8n!HZRGk=g*im~gvfxiIlE*P>K6TcT?;k5C4VU}k6Ml#iuZ)nPO zwB~1*|NgEof}0mYtcLKtNbmRqrA0|*u|zUX_+Ffas|w%F3n7-k2x08Tr*Q0El2&x= zUWzD}wkYct^!85h4OinIHH^S17`&Y5y$qXC(R*2p*VQVB-b2&~UXFm4?;Ur1w1RFs z6um8AxgwAzM(>pfSV!-bX?YdT6$qxbMdbjvE9d|xdJkn~XJ)6E0dg4Hw9(rdl&dO- ztVUR?TUaJ~1FmnIVK@tp2o;RN>})fPtOB!ljb{xSU9-H=uw<--!rhRJQSg^uC9h5M z>$v8XWUNagbDd;hSZc|D=Md1>105|H>yyp~VLGGv$Qf92LsW~G3^)fCHnIcECmCbZ z_}Z8@H*sxJGJqw$WNgY-#)evniWrV$Y!>8|V#4?&V;t>{57~{8j0r59Rx&ncX-dXu z6%RUOenxY#Ip1EPYU~8n*djqSwj`ge68Si)u{8^KS2ZSLkWe-7DXbdX(27=#ZHcnh zqO4!UuNsbv)L;UwVBB`B_gkyV*+MOy8jvdrE-jSFl#R|t{-8O~8xqu4cu$W~X zz$R+PPQNAt$1bez%<>eoLGFq+DIYHMAPZn$l6^w%ID9Bz_!1fd*OQTcD8x1Q+BMNszL7Lz)tsps?pX!=d3NnpG z<~jwz;M58N&mq1G(9sIgOgb%LI@9^c8C$Xy)#4Qd&VhwCJH~tp(yqo=o;EvNn^X{B zNv|LUwjx8VM1>AVL5e|MDdvn%K}xjS8L}IrATwAvt%A&CX)4INDk|{TIxAFM@5_w0i7El>1wh?yHv7TXnM1zIhImf+5pU zjsw_=QjP;LTDPb`ISx|e_h8~VBvv^N)ooKb=JTr^yHg$ppoyw+IPq%L=%V2xJV#)5 z`QI}KUj^wqig6_CI(=$A*KO}m9)?8&2*H;y5wV=XA7769v0i{n`E_)x(p$c|c^ zPz7X9El#A-lgb+ntHsGE+zquj1@6*naVpK9=9*V(aXO96b!ve@snr6WLo7c7bhKKW zNjhhR>730+&bX52pjy0Iz&WsRu5WzV7tEcf#@G3@d4X$_Y5^?i)#5_7a#5(2sBqz^ z#l=BhDdvk$EiR$mOG9>J)Z#K0POBD|vozIW9TN@WUN9HALA5l*;)(>ZxRO+^N~Ge5 z#nmj_U9q?ZPhqjRmR7V_Tt}4GTa>=tdi@SF^A0&M3IEfr28x+BNTw@6N>v;@PSalD8!CXJXi%{PbeOu(TB?$ z4GYC1DBKO9cog2!Lh%^QKkk}WLh%HR%ymM6A*qD|oY*2K?RYk-iiXFV4QSB;zKr~MB*ci)5|IliI3ID{e*BnjTMQ{ zblVgO{6wa{unM^Hb6`vqh%X3L3&fYS`IYB_UTRRNIRgg;Nju{3HLE$ZIK^m}-=Iy3 zgEl3a zOJjhs2n-O(ez(5h_kZxizJDlZ{7GAXSzE>#z+j`8x*LffRn#Z(f3wyQ1poC6E}QPeJ@?J{RTAD+b5(B?qbCPxgg*nUqui66vP28UXS3Sy3W%@gF6Vm|xS zYhK!&FJw1Hz2;}(wCc40OH;i@C4AY_x59D0)_E!PYr#J8r|=7r$ij(49Q|5^g{#sp z|0SwLF+eC`_!O3~#b`)N*y04bgayjoe4`28D?Gs`7|0#GcUO0Dfk;>%&GEu&kCsr+AE70hQ9)0sYN;PZXogi&TzgA*BXC9{* z?{a0d$@yz+$yJmGh7!y$3&zB3fK&pe!}O{wxLT;7g&PjjtD|r?!t`*U)?s=C&5v}= zt3}2dG&0vMGB7T5n1<&NMArlzy~tRLbVh~gtj$MG_sVrpEj~=cIk2#(k~2u1$t%U`ZdQN3)d;L#;&3Rwqnv6y%j+*!sfs7~0)9WH%;EZ^FW9!}O*sZ5J8E ziWeEXB1n%-2-2I8#<)ZpPLLkY!c_%n=c?2Mj15L;d0dlH3j$ z6NB~kgsOw}4z#(W=LswTiaEX3fS-b-omf4I)tt$kV$jRUXw$AW0J~1n--%Fmwopu{ z21MUl19$u9$X!AOqtH5Qja{ojyBjO%#m4S5yoWVxR|q;*@0rE|V-hGJqBU4&*u}

a13jFxr*^kwfOM;Q?@0iDS(33nyobh5GVow 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

P)9u(zbI*PADXRTIr>AFm+ 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 RUpI6czC`>UrJQl<{{YNrSrh;O literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.openvswitch.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.openvswitch.doctree new file mode 100644 index 0000000000000000000000000000000000000000..3ede8d5a5c63718361a62ed1dd70fbb0879b9983 GIT binary patch literal 59649 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 PNjWM_JgXK}?u7pbP!s93 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.util.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.util.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d114ec2dfc1bcf990daa827cfeedd07cfad85164 GIT binary patch literal 315318 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 z

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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.util.parsers.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.util.parsers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..c281d945c1406c19a2be248045c23fe53b68b1e7 GIT binary patch literal 15545 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 *2Qb^^i~)&OuHe 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


`K4tL% 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�*RmYMe?!yp}UU(!v$s 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¨%4 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 CGvvzv literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/index.doctree b/doc/sphinx/_build/doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..cef08a5659579377ed4b103403f6458e82b3a7fa GIT binary patch literal 21584 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 Z^dX*(K8*Nb`ys33(MQ + + + + + + + nepi — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

This Page

+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.data.html b/doc/sphinx/_build/html/_layout/nepi.data.html new file mode 100644 index 00000000..5199c38f --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.data.html @@ -0,0 +1,134 @@ + + + + + + + + nepi.data package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.data.processing.ccn.html b/doc/sphinx/_build/html/_layout/nepi.data.processing.ccn.html new file mode 100644 index 00000000..49ad55d6 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.data.processing.ccn.html @@ -0,0 +1,174 @@ + + + + + + + + nepi.data.processing.ccn package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.data.processing.ccn package¶

+
+

Submodules¶

+
+
+

nepi.data.processing.ccn.parser module¶

+
+
+nepi.data.processing.ccn.parser.annotate_cn_graph(logs_dir, graph, parse_ping_logs=False)[source]¶
+

Adds CCN content history for each node in the topology graph.

+
+ +
+
+nepi.data.processing.ccn.parser.annotate_cn_node(graph, nid, ips2nid, data, content_history)[source]¶
+
+ +
+
+nepi.data.processing.ccn.parser.ccn_consumers(graph)[source]¶
+

Returns the nodes that are content consumers

+
+ +
+
+nepi.data.processing.ccn.parser.ccn_producers(graph)[source]¶
+

Returns the nodes that are content providers

+
+ +
+
+nepi.data.processing.ccn.parser.dump_content_history(content_history)[source]¶
+
+ +
+
+nepi.data.processing.ccn.parser.is_control(content_name)[source]¶
+
+ +
+
+nepi.data.processing.ccn.parser.load_content_history(fname)[source]¶
+
+ +
+
+nepi.data.processing.ccn.parser.parse_file(filename)[source]¶
+

Parses message information from ccnd log files

+

filename: path to ccndlog file

+
+ +
+
+nepi.data.processing.ccn.parser.process_content_history(graph)[source]¶
+

Compute CCN message counts and aggregates content historical +information in the content_names dictionary

+
+ +
+
+nepi.data.processing.ccn.parser.process_content_history_logs(logs_dir, graph, parse_ping_logs=False)[source]¶
+

Parse CCN logs and aggregate content history information in graph. +Returns annotated graph and message countn and content names history.

+
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.data.processing.html b/doc/sphinx/_build/html/_layout/nepi.data.processing.html new file mode 100644 index 00000000..4fb2e10a --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.data.processing.html @@ -0,0 +1,127 @@ + + + + + + + + nepi.data.processing package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.data.processing.ping.html b/doc/sphinx/_build/html/_layout/nepi.data.processing.ping.html new file mode 100644 index 00000000..c9162d9c --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.data.processing.ping.html @@ -0,0 +1,133 @@ + + + + + + + + nepi.data.processing.ping package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.data.processing.ping package¶

+
+

Submodules¶

+
+
+

nepi.data.processing.ping.parser module¶

+
+
+nepi.data.processing.ping.parser.annotate_cn_graph(logs_dir, graph)[source]¶
+

Add delay inormation to graph using data collected using +ping.

+
+ +
+
+nepi.data.processing.ping.parser.annotate_cn_node(graph, nid1, ips2nid, data)[source]¶
+
+ +
+
+nepi.data.processing.ping.parser.parse_file(filename)[source]¶
+

filename: path to traceroute file

+
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.execution.html b/doc/sphinx/_build/html/_layout/nepi.execution.html new file mode 100644 index 00000000..75b38a02 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.execution.html @@ -0,0 +1,2376 @@ + + + + + + + + nepi.execution package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

nepi.execution package¶

+
+

Submodules¶

+
+
+

nepi.execution.attribute module¶

+
+
+class nepi.execution.attribute.Attribute(name, help, type='STRING', flags=None, default=None, allowed=None, range=None, set_hook=None)[source]¶
+

Bases: object

+

An Attribute exposes a configuration parameter of a resource

+
+
+allowed[source]¶
+

Returns the set of allowed values for the Attribute

+
+ +
+
+default[source]¶
+

Returns the default value of the Attribute

+
+ +
+
+flags[source]¶
+

Returns the flags of the Attribute

+
+ +
+
+get_value()[source]¶
+

Returns the value of the Attribute

+
+ +
+
+has_changed[source]¶
+

Returns True if the value has changed from the default

+
+ +
+
+has_flag(flag)[source]¶
+

Returns True if the Attribute has the flag ‘flag’

+ +++ + + + +
Parameters:flag (Flags) – Flag to be checked
+
+ +
+
+help[source]¶
+

Returns the description of the Attribute

+
+ +
+
+is_valid_value(value)[source]¶
+

Attribute subclasses will override this method to add +adequate validation

+
+ +
+
+name[source]¶
+

Returns the name of the Attribute

+
+ +
+
+range[source]¶
+

Returns the range of allowed numerical values for the Attribute

+
+ +
+
+set_value(value)[source]¶
+

Configure a new value for the Attribute

+
+ +
+
+type[source]¶
+

Returns the type of the Attribute

+
+ +
+
+value¶
+

Returns the value of the Attribute

+
+ +
+ +
+
+class nepi.execution.attribute.Flags[source]¶
+

Flags to characterize the scope of an Attribute

+
+
+Construct = 8¶
+
+ +
+
+Credential = 20¶
+
+ +
+
+Design = 4¶
+
+ +
+
+Filter = 36¶
+
+ +
+
+Global = 128¶
+
+ +
+
+NoRead = 1¶
+
+ +
+
+NoWrite = 2¶
+
+ +
+
+Reserved = 64¶
+
+ +
+ +
+
+class nepi.execution.attribute.Types[source]¶
+

Allowed types for the Attribute value

+
+
+Bool = 'BOOL'¶
+
+ +
+
+Double = 'DOUBLE'¶
+
+ +
+
+Enumerate = 'ENUM'¶
+
+ +
+
+Integer = 'INTEGER'¶
+
+ +
+
+String = 'STRING'¶
+
+ +
+ +
+
+

nepi.execution.ec module¶

+
+
+class nepi.execution.ec.ECState[source]¶
+

Bases: object

+

Possible states of the ExperimentController

+
+
+FAILED = 2¶
+
+ +
+
+RELEASED = 3¶
+
+ +
+
+RUNNING = 1¶
+
+ +
+
+TERMINATED = 4¶
+
+ +
+ +
+
+class nepi.execution.ec.ExperimentController(exp_id=None, local_dir=None, persist=False, fm=None, add_node_callback=None, add_edge_callback=None, **kwargs)[source]¶
+

Bases: object

+

An experiment, or scenario, is defined by a concrete set of resources, +and the behavior, configuration and interconnection of those resources. +The Experiment Description (ED) is a detailed representation of a +single experiment. It contains all the necessary information to +allow repeating the experiment. NEPI allows to describe +experiments by registering components (resources), configuring them +and interconnecting them.

+

A same experiment (scenario) can be executed many times, generating +different results. We call an experiment execution (instance) a ‘run’.

+

The ExperimentController (EC), is the entity responsible of +managing an experiment run. The same scenario can be +recreated (and re-run) by instantiating an EC and recreating +the same experiment description.

+

An experiment is represented as a graph of interconnected +resources. A resource is a generic concept in the sense that any +component taking part of an experiment, whether physical of +virtual, is considered a resource. A resources could be a host, +a virtual machine, an application, a simulator, a IP address.

+

A ResourceManager (RM), is the entity responsible for managing a +single resource. ResourceManagers are specific to a resource +type (i.e. An RM to control a Linux application will not be +the same as the RM used to control a ns-3 simulation). +To support a new type of resource, a new RM must be implemented. +NEPI already provides a variety of RMs to control basic resources, +and new can be extended from the existing ones.

+

Through the EC interface the user can create ResourceManagers (RMs), +configure them and interconnect them, to describe an experiment. +Describing an experiment through the EC does not run the experiment. +Only when the ‘deploy()’ method is invoked on the EC, the EC will take +actions to transform the ‘described’ experiment into a ‘running’ experiment.

+

While the experiment is running, it is possible to continue to +create/configure/connect RMs, and to deploy them to involve new +resources in the experiment (this is known as ‘interactive’ deployment).

+

An experiments in NEPI is identified by a string id, +which is either given by the user, or automatically generated by NEPI. +The purpose of this identifier is to separate files and results that +belong to different experiment scenarios. +However, since a same ‘experiment’ can be run many times, the experiment +id is not enough to identify an experiment instance (run). +For this reason, the ExperimentController has two identifier, the +exp_id, which can be re-used in different ExperimentController, +and the run_id, which is unique to one ExperimentController instance, and +is automatically generated by NEPI.

+
+
+abort[source]¶
+

Returns True if the experiment has failed and should be interrupted, +False otherwise.

+
+ +
+
+deploy(guids=None, wait_all_ready=True, group=None)[source]¶
+

Deploys all ResourceManagers in the guids list.

+

If the argument ‘guids’ is not given, all RMs with state NEW +are deployed.

+
+
+++ + + + + + + + + + + + + + + +
param guids:List of guids of RMs to deploy
type guids:list
param wait_all_ready:
 Wait until all RMs are ready in +order to start the RMs
type guid:int
param group:Id of deployment group in which to deploy RMs
type group:int
+
+
+ +
+
+discover(guid)[source]¶
+

Discovers an available resource matching the criteria defined +by the RM with guid ‘guid’, and associates that resource to the RM

+

Not all RM types require (or are capable of) performing resource +discovery. For the RM types which are not capable of doing so, +invoking this method does not have any consequences.

+
+
+++ + + + + + +
param guid:Guid of the RM
type guid:int
+
+
+ +
+
+ecstate[source]¶
+

Returns the state of the Experiment Controller

+
+ +
+
+enable_trace(guid, name)[source]¶
+

Enables a trace to be collected during the experiment run

+ +++ + + + +
Parameters:name (str) – Name of the trace
+
+ +
+
+exp_dir[source]¶
+

Local directory to store results and other files related to the +experiment.

+
+ +
+
+exp_id[source]¶
+

Returns the experiment id assigned by the user

+
+ +
+
+failure_level[source]¶
+

Returns the level of FAILURE of th experiment

+
+ +
+
+filter_resources(rtype)[source]¶
+

Returns the guids of all ResourceManagers of type rtype

+ +++ + + + + + +
Parameters:rtype (string) – Resource type
Return type:list of guids
+
+ +
+
+fm[source]¶
+

Returns the failure manager

+
+ +
+
+get(guid, name)[source]¶
+

Returns the value of the attribute with name ‘name’ on the +RM with guid ‘guid’

+
+
+++ + + + + + + + + + + + +
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’
+
+
+ +
+
+get_attribute(guid, name)[source]¶
+

Returns the attribute ‘name’ of the RM with guid ‘guid’

+ +++ + + + + + + + +
Parameters:
    +
  • guid (int) – Guid of the RM
  • +
  • name (str) – Name of the attribute
  • +
+
Returns:

The attribute with name ‘name’

+
Return type:

Attribute

+
+
+ +
+
+get_attributes(guid)[source]¶
+

Returns all the attributes of the RM with guid ‘guid’

+ +++ + + + + + + + +
Parameters:guid (int) – Guid of the RM
Returns:List of attributes
Return type:list
+
+ +
+
+get_discover_time(guid)[source]¶
+

Returns the discover time of the RM as a timestamp

+
+ +
+
+get_failed_time(guid)[source]¶
+

Returns the time failure occured for the RM as a timestamp

+
+ +
+
+get_global(rtype, name)[source]¶
+

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’
+
+
+ +
+
+get_provision_time(guid)[source]¶
+

Returns the provision time of the RM as a timestamp

+
+ +
+
+get_ready_time(guid)[source]¶
+

Returns the deployment time of the RM as a timestamp

+
+ +
+
+get_release_time(guid)[source]¶
+

Returns the release time of the RM as a timestamp

+
+ +
+
+get_resource(guid)[source]¶
+

Returns a registered ResourceManager by its guid

+ +++ + + + + + +
Parameters:guid (int) – Id of the resource
Return type:ResourceManager
+
+ +
+
+get_resources_by_type(rtype)[source]¶
+

Returns the ResourceManager objects of type rtype

+ +++ + + + + + +
Parameters:rtype (string) – Resource type
Return type:list of ResourceManagers
+
+ +
+
+get_start_time(guid)[source]¶
+

Returns the start time of the RM as a timestamp

+
+ +
+
+get_stop_time(guid)[source]¶
+

Returns the stop time of the RM as a timestamp

+
+ +
+
+get_task(tid)[source]¶
+

Returns a task by its id

+ +++ + + + + + +
Parameters:tid (int) – Id of the task
Return type:Task
+
+ +
+
+get_traces(guid)[source]¶
+

Returns the list of the trace names of the RM with guid ‘guid’

+ +++ + + + + + + + +
Parameters:guid (int) – Guid of the RM
Returns:List of trace names
Return type:list
+
+ +
+
+inform_failure(guid)[source]¶
+

Reports a failure in a RM to the EC for evaluation

+ +++ + + + +
Parameters:guid (int) – Resource id
+
+ +
+
+classmethod load(filepath, format='xml')[source]¶
+
+ +
+
+local_dir[source]¶
+

Root local directory for experiment files

+
+ +
+
+logger[source]¶
+

Returns the logger instance of the Experiment Controller

+
+ +
+
+netgraph[source]¶
+

Return NetGraph instance if experiment description was automatically +generated

+
+ +
+
+nthreads[source]¶
+

Returns the number of processing nthreads used

+
+ +
+
+persist[source]¶
+

If True, persists the ExperimentController to XML format upon +experiment completion

+
+ +
+
+plot(dirpath=None, format='figure', show=False)[source]¶
+
+ +
+
+provision(guid)[source]¶
+

Provisions the resource associated to the RM with guid ‘guid’.

+

Provisioning means making a resource ‘accessible’ to the user. +Not all RM types require (or are capable of) performing resource +provisioning. For the RM types which are not capable of doing so, +invoking this method does not have any consequences.

+
+
+++ + + + + + +
param guid:Guid of the RM
type guid:int
+
+
+ +
+
+register_condition(guids1, action, guids2, state, time=None)[source]¶
+

Registers an action START, STOP or DEPLOY for all RM on list +guids1 to occur at time ‘time’ after all elements in list guids2 +have reached state ‘state’.

+
+
+++ + + + + + + + + + + + + + + + + + + + + + +
param guids1:List of guids of RMs subjected to action
type guids1:list
param action:Action to perform (either START, STOP or DEPLOY)
type action:ResourceAction
param guids2:List of guids of RMs to we waited for
type guids2:list
param state:State to wait for on RMs of list guids2 (STARTED, +STOPPED, etc)
type state:ResourceState
param time:Time to wait after guids2 has reached status
type time:string
+
+
+ +
+
+register_connection(guid1, guid2)[source]¶
+

Registers a connection between a RM with guid ‘guid1’ +and another RM with guid ‘guid2’.

+

The order of the in which the two guids are provided is not +important, since the connection relationship is symmetric.

+
+
+++ + + + + + + + + + +
param guid1:First guid to connect
type guid1:ResourceManager
param guid2:Second guid to connect
type guid:ResourceManager
+
+
+ +
+
+register_resource(rtype, guid=None)[source]¶
+

Registers a new ResourceManager of type ‘rtype’ in the experiment

+

This method will assign a new ‘guid’ for the RM, if no guid +is specified.

+
+
+++ + + + + + + + + + +
param rtype:Type of the RM
type rtype:str
return:Guid of the RM
rtype:int
+
+
+ +
+
+release(guids=None)[source]¶
+

Releases all ResourceManagers in the guids list.

+

If the argument ‘guids’ is not given, all RMs registered +in the experiment are released.

+
+
+++ + + + + + +
param guids:List of RM guids
type guids:list
+
+
+ +
+
+remove_resource(guid)[source]¶
+
+ +
+
+resources[source]¶
+

Returns the guids of all ResourceManagers

+ +++ + + + + + +
Returns:Set of all RM guids
Return type:list
+
+ +
+
+run_dir[source]¶
+

Local directory to store results and other files related to the +experiment run.

+
+ +
+
+run_id[source]¶
+

Returns the experiment instance (run) identifier (automatically +generated)

+
+ +
+
+save(dirpath=None, format='xml')[source]¶
+
+ +
+
+schedule(date, callback, track=False)[source]¶
+

Schedules a callback to be executed at time ‘date’.

+ +++ + + + +
Parameters:
    +
  • date – string containing execution time for the task. +It can be expressed as an absolute time, using +timestamp format, or as a relative time matching +^d+.d+(h|m|s|ms|us)$
  • +
  • callback – code to be executed for the task. Must be a +Python function, and receives args and kwargs +as arguments.
  • +
  • track – if set to True, the task will be retrievable with +the get_task() method
  • +
+
+

:return : The Id of the task +:rtype: int

+
+ +
+
+serialize(format='xml')[source]¶
+
+ +
+
+set(guid, name, value)[source]¶
+

Modifies the value of the attribute with name ‘name’ on the +RM with guid ‘guid’.

+
+
+++ + + + + + + + + + + + +
param guid:Guid of the RM
type guid:int
param name:Name of the attribute
type name:str
param value:Value of the attribute
+
+
+ +
+
+set_global(rtype, name, value)[source]¶
+

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
+
+
+ +
+
+set_with_conditions(name, value, guids1, guids2, state, time=None)[source]¶
+

Modifies the value of attribute with name ‘name’ on all RMs +on the guids1 list when time ‘time’ has elapsed since all +elements in guids2 list have reached state ‘state’.

+
+
+++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
param name:Name of attribute to set in RM
type name:string
param value:Value of attribute to set in RM
type name:string
param guids1:List of guids of RMs subjected to action
type guids1:list
param action:Action to register (either START or STOP)
type action:ResourceAction
param guids2:List of guids of RMs to we waited for
type guids2:list
param state:State to wait for on RMs (STARTED, STOPPED, etc)
type state:ResourceState
param time:Time to wait after guids2 has reached status
type time:string
+
+
+ +
+
+shutdown()[source]¶
+

Releases all resources and stops the ExperimentController

+
+ +
+
+start(guid)[source]¶
+

Starts the RM with guid ‘guid’

+

Starting a RM means that the resource it controls will +begin taking part of the experiment.

+
+
+++ + + + + + +
param guid:Guid of the RM
type guid:int
+
+
+ +
+
+state(guid, hr=False)[source]¶
+

Returns the state of a resource

+ +++ + + + +
Parameters:
    +
  • guid (integer) – Resource guid
  • +
  • hr (boolean) – Human readable. Forces return of a +status string instead of a number
  • +
+
+
+ +
+
+stop(guid)[source]¶
+

Stops the RM with guid ‘guid’

+

Stopping a RM means that the resource it controls will +no longer take part of the experiment.

+
+
+++ + + + + + +
param guid:Guid of the RM
type guid:int
+
+
+ +
+
+trace(guid, name, attr='all', block=512, offset=0)[source]¶
+

Returns information on a collected trace, the trace stream or +blocks (chunks) of the trace stream

+
+
+++ + + + + + + + + + + + + + + + + + + + +
param name:

Name of the trace

+
type name:

str

+
param attr:

Can be one of: +- TraceAttr.ALL (complete trace content), +- TraceAttr.STREAM (block in bytes to read starting

+
+

at offset),

+
+
    +
  • TraceAttr.PATH (full path to the trace file),
  • +
  • TraceAttr.SIZE (size of trace file).
  • +
+
type attr:

str

+
param block:

Number of bytes to retrieve from trace, when attr is +TraceAttr.STREAM

+
type name:

int

+
param offset:

Number of ‘blocks’ to skip, when attr is TraceAttr.STREAM

+
type name:

int

+
rtype:

str

+
+
+
+ +
+
+trace_enabled(guid, name)[source]¶
+

Returns True if the trace of name ‘name’ is enabled

+ +++ + + + +
Parameters:name (str) – Name of the trace
+
+ +
+
+wait(guids, state, quit)[source]¶
+

Blocking method that waits until all RMs in the ‘guids’ list +have reached a state >= ‘state’, or until the ‘quit’ callback +yields True

+
+
+++ + + + + + +
param guids:List of guids
type guids:list
+
+
+ +
+
+wait_deployed(guids)[source]¶
+

Blocking method that waits until all RMs in the ‘guids’ list +have reached a state >= READY, or until a failure in the +experiment occurs (i.e. abort == True)

+
+
+++ + + + + + +
param guids:List of guids
type guids:list
+
+
+ +
+
+wait_finished(guids)[source]¶
+

Blocking method that waits until all RMs in the ‘guids’ list +have reached a state >= STOPPED (i.e. STOPPED, FAILED or +RELEASED ), or until a failure in the experiment occurs +(i.e. abort == True)

+
+
+++ + + + + + +
param guids:List of guids
type guids:list
+
+
+ +
+
+wait_released(guids)[source]¶
+

Blocking method that waits until all RMs in the ‘guids’ list +have reached a state == RELEASED, or until the EC fails

+
+
+++ + + + + + +
param guids:List of guids
type guids:list
+
+
+ +
+
+wait_started(guids)[source]¶
+

Blocking method that waits until all RMs in the ‘guids’ list +have reached a state >= STARTED, or until a failure in the +experiment occurs (i.e. abort == True)

+
+
+++ + + + + + +
param guids:List of guids
type guids:list
+
+
+ +
+ +
+
+class nepi.execution.ec.FailureLevel[source]¶
+

Bases: object

+

Possible failure states for the experiment

+
+
+EC_FAILURE = 3¶
+
+ +
+
+OK = 1¶
+
+ +
+
+RM_FAILURE = 2¶
+
+ +
+ +
+
+class nepi.execution.ec.FailureManager[source]¶
+

Bases: object

+

The FailureManager is responsible for handling errors +and deciding whether an experiment should be aborted or not

+
+
+abort[source]¶
+
+ +
+
+ec[source]¶
+

Returns the ExperimentController associated to this FailureManager

+
+ +
+
+eval_failure(guid)[source]¶
+

Implements failure policy and sets the abort state of the +experiment based on the failure state and criticality of +the RM

+ +++ + + + +
Parameters:guid (int) – Guid of the RM upon which the failure of the experiment +is evaluated
+
+ +
+
+set_ec(ec)[source]¶
+
+ +
+
+set_ec_failure()[source]¶
+
+ +
+ +
+
+

nepi.execution.resource module¶

+
+
+class nepi.execution.resource.ResourceAction[source]¶
+

Action that a user can order to a Resource Manager

+
+
+DEPLOY = 0¶
+
+ +
+
+START = 1¶
+
+ +
+
+STOP = 2¶
+
+ +
+ +
+
+class nepi.execution.resource.ResourceFactory[source]¶
+

Bases: object

+
+
+classmethod create(rtype, ec, guid)[source]¶
+

Create a new instance of a Ressource Manager

+
+ +
+
+classmethod get_resource_type(rtype)[source]¶
+

Return the type of the Class

+
+ +
+
+classmethod register_type(rclass)[source]¶
+

Register a new Ressource Manager

+
+ +
+
+classmethod resource_types()[source]¶
+

Return the type of the Class

+
+ +
+ +
+
+class nepi.execution.resource.ResourceManager(ec, guid)[source]¶
+

Bases: nepi.util.logger.Logger

+

Base clase for all ResourceManagers.

+

A ResourceManger is specific to a resource type (e.g. Node, +Switch, Application, etc) on a specific platform (e.g. PlanetLab, +OMF, etc).

+

The ResourceManager instances are responsible for interacting with +and controlling concrete (physical or virtual) resources in the +experimental platforms.

+
+
+conditions[source]¶
+

Returns the conditions to which the RM is subjected to.

+

This method returns a dictionary of conditions lists indexed by +a ResourceAction.

+
+ +
+
+configure(*args, **kwargs)[source]¶
+
+ +
+
+connections[source]¶
+

Returns the set of guids of connected RMs

+
+ +
+
+deploy(*args, **kwargs)[source]¶
+
+ +
+
+deploy_with_conditions()[source]¶
+

Deploy RM when all the conditions in self.conditions for +action ‘READY’ are satisfied.

+
+ +
+
+discover(*args, **kwargs)[source]¶
+
+ +
+
+discover_time[source]¶
+

Returns the discover time of the RM as a timestamp

+
+ +
+
+do_configure()[source]¶
+
+ +
+
+do_connect(guid)[source]¶
+

Performs actions that need to be taken upon associating RMs. +This method should be redefined when necessary in child classes.

+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_disconnect(guid)[source]¶
+

Performs actions that need to be taken upon disassociating RMs. +This method should be redefined when necessary in child classes.

+
+ +
+
+do_discover()[source]¶
+
+ +
+
+do_fail()[source]¶
+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_release()[source]¶
+
+ +
+
+do_reserve()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+ec[source]¶
+

Returns the Experiment Controller of the RM

+
+ +
+
+enable_trace(name)[source]¶
+

Explicitly enable trace generation

+ +++ + + + +
Parameters:name (str) – Name of the trace
+
+ +
+
+fail()[source]¶
+

Sets the RM to state FAILED.

+

This method should not be overridden directly. Specific functionality +should be added in the do_fail method.

+
+ +
+
+failed_time[source]¶
+

Returns the time failure occurred for the RM as a timestamp

+
+ +
+
+get(name)[source]¶
+

Returns the value of the attribute

+ +++ + + + + + +
Parameters:name (str) – Name of the attribute
Return type:str
+
+ +
+
+classmethod get_attribute(name)[source]¶
+

Returns a copy of the attribute with name ‘name’

+
+ +
+
+classmethod get_attributes()[source]¶
+

Returns a copy of the attributes

+
+ +
+
+get_connected(rtype=None)[source]¶
+

Returns the list of RM with the type ‘rtype’

+ +++ + + + + + +
Parameters:rtype (str) – Type of the RM we look for
Returns:list of guid
+
+ +
+
+classmethod get_global(name)[source]¶
+
+
Returns the value of a global attribute
+
Global attribute meaning an attribute for +all the resources from a rtype
+
+ +++ + + + + + +
Parameters:name (str) – Name of the attribute
Return type:str
+
+ +
+
+classmethod get_help()[source]¶
+

Returns the description of the type of Resource

+
+ +
+
+classmethod get_platform()[source]¶
+

Returns the identified of the platform (i.e. testbed type) +for the Resource

+
+ +
+
+classmethod get_rtype()[source]¶
+

Returns the type of the Resource Manager

+
+ +
+
+classmethod get_traces()[source]¶
+

Returns a copy of the traces

+
+ +
+
+guid[source]¶
+

Returns the global unique identifier of the RM

+
+ +
+
+has_attribute(name)[source]¶
+

Returns true if the RM has an attribute with name

+ +++ + + + +
Parameters:name (string) – name of the attribute
+
+ +
+
+has_changed(name)[source]¶
+
+
Returns the True is the value of the attribute
+
has been modified by the user.
+
+ +++ + + + + + +
Parameters:name (str) – Name of the attribute
Return type:str
+
+ +
+
+has_flag(name, flag)[source]¶
+

Returns true if the attribute has the flag ‘flag’

+ +++ + + + +
Parameters:flag (Flags) – Flag to be checked
+
+ +
+
+is_rm_instance(rtype)[source]¶
+

Returns True if the RM is instance of ‘rtype’

+ +++ + + + + + +
Parameters:rtype (str) – Type of the RM we look for
Returns:True|False
+
+ +
+
+log_message(msg)[source]¶
+

Returns the log message formatted with added information.

+ +++ + + + + + +
Parameters:msg (str) – text message
Return type:str
+
+ +
+
+provision(*args, **kwargs)[source]¶
+
+ +
+
+provision_time[source]¶
+

Returns the provision time of the RM as a timestamp

+
+ +
+
+ready_time[source]¶
+

Returns the deployment time of the RM as a timestamp

+
+ +
+
+register_condition(action, group, state, time=None)[source]¶
+

Registers a condition on the resource manager to allow execution +of ‘action’ only after ‘time’ has elapsed from the moment all resources +in ‘group’ reached state ‘state’

+ +++ + + + +
Parameters:
    +
  • action (str) – Action to restrict to condition (either ‘START’ or ‘STOP’)
  • +
  • group (int or list of int) – Group of RMs to wait for (list of guids)
  • +
  • state (str) – State to wait for on all RM in group. (either ‘STARTED’, ‘STOPPED’ or ‘READY’)
  • +
  • time (str) – Time to wait after ‘state’ is reached on all RMs in group. (e.g. ‘2s’)
  • +
+
+
+ +
+
+register_connection(guid)[source]¶
+

Registers a connection to the RM identified by guid

+

This method should not be overridden. Specific functionality +should be added in the do_connect method.

+ +++ + + + +
Parameters:guid (int) – Global unique identified of the RM to connect to
+
+ +
+
+release()[source]¶
+

Perform actions to free resources used by the RM.

+

This method is responsible for releasing resources that were +used during the experiment by the RM.

+

This method should not be overridden directly. Specific functionality +should be added in the do_release method.

+
+ +
+
+release_time[source]¶
+

Returns the release time of the RM as a timestamp

+
+ +
+
+reschedule_delay[source]¶
+

Returns default reschedule delay

+
+ +
+
+reserve(*args, **kwargs)[source]¶
+
+ +
+
+reserved_time[source]¶
+

Returns the reserved time of the RM as a timestamp

+
+ +
+
+set(name, value)[source]¶
+

Set the value of the attribute

+ +++ + + + +
Parameters:
    +
  • name (str) – Name of the attribute
  • +
  • name – Value of the attribute
  • +
+
+
+ +
+
+set_discovered(time=None)[source]¶
+

Mark ResourceManager as DISCOVERED

+
+ +
+
+set_failed(time=None)[source]¶
+

Mark ResourceManager as FAILED

+
+ +
+
+classmethod set_global(name, value)[source]¶
+

Set value for a global attribute

+ +++ + + + +
Parameters:
    +
  • name (str) – Name of the attribute
  • +
  • name – Value of the attribute
  • +
+
+
+ +
+
+set_provisioned(time=None)[source]¶
+

Mark ResourceManager as PROVISIONED

+
+ +
+
+set_ready(time=None)[source]¶
+

Mark ResourceManager as READY

+
+ +
+
+set_released(time=None)[source]¶
+

Mark ResourceManager as REALEASED

+
+ +
+
+set_reserved(time=None)[source]¶
+

Mark ResourceManager as RESERVED

+
+ +
+
+set_started(time=None)[source]¶
+

Mark ResourceManager as STARTED

+
+ +
+
+set_state(state, state_time_attr, time=None)[source]¶
+

Set the state of the RM while keeping a trace of the time

+
+ +
+
+set_state_time(state, state_time_attr, time)[source]¶
+

Set the time for the RM state change

+
+ +
+
+set_stopped(time=None)[source]¶
+

Mark ResourceManager as STOPPED

+
+ +
+
+set_with_conditions(name, value, group, state, time)[source]¶
+

Set value ‘value’ on attribute with name ‘name’ when ‘time’ +has elapsed since all elements in ‘group’ have reached state +‘state’

+ +++ + + + +
Parameters:
    +
  • name (str) – Name of the attribute to set
  • +
  • name – Value of the attribute to set
  • +
  • group (int or list of int) – Group of RMs to wait for (list of guids)
  • +
  • state (str) – State to wait for on all RM in group. (either ‘STARTED’, ‘STOPPED’ or ‘READY’)
  • +
  • time (str) – Time to wait after ‘state’ is reached on all RMs in group. (e.g. ‘2s’)
  • +
+
+
+ +
+
+start(*args, **kwargs)[source]¶
+
+ +
+
+start_time[source]¶
+

Returns the start time of the RM as a timestamp

+
+ +
+
+start_with_conditions()[source]¶
+

Starts RM when all the conditions in self.conditions for +action ‘START’ are satisfied.

+
+ +
+
+state[source]¶
+

Get the current state of the RM

+
+ +
+
+stop(*args, **kwargs)[source]¶
+
+ +
+
+stop_time[source]¶
+

Returns the stop time of the RM as a timestamp

+
+ +
+
+stop_with_conditions()[source]¶
+

Stops RM when all the conditions in self.conditions for +action ‘STOP’ are satisfied.

+
+ +
+
+trace(name, attr='all', block=512, offset=0)[source]¶
+

Get information on collected trace

+ +++ + + + + + +
Parameters:
    +
  • name (int) – Name of the trace
  • +
  • attr (str) – Can be one of: +- TraceAttr.ALL (complete trace content), +- TraceAttr.STREAM (block in bytes to read starting at offset), +- TraceAttr.PATH (full path to the trace file), +- TraceAttr.SIZE (size of trace file).
  • +
  • block – Number of bytes to retrieve from trace, when attr is TraceAttr.STREAM
  • +
  • offset – Number of ‘blocks’ to skip, when attr is TraceAttr.STREAM
  • +
+
Return type:

str

+
+
+ +
+
+trace_enabled(name)[source]¶
+

Returns True if trace is enables

+ +++ + + + +
Parameters:name (str) – Name of the trace
+
+ +
+
+unregister_condition(group, action=None)[source]¶
+

Removed conditions for a certain group of guids

+ +++ + + + +
Parameters:
    +
  • action (str) – Action to restrict to condition (either ‘START’, ‘STOP’ or ‘READY’)
  • +
  • group (int or list of int) – Group of RMs to wait for (list of guids)
  • +
+
+
+ +
+
+unregister_connection(guid)[source]¶
+

Removes a registered connection to the RM identified by guid

+

This method should not be overridden. Specific functionality +should be added in the do_disconnect method.

+ +++ + + + +
Parameters:guid (int) – Global unique identified of the RM to connect to
+
+ +
+
+valid_connection(guid)[source]¶
+

Checks whether a connection with the other RM +is valid. +This method need to be redefined by each new Resource Manager.

+ +++ + + + + + +
Parameters:guid (int) – Guid of the current Resource Manager
Return type:Boolean
+
+ +
+ +
+
+class nepi.execution.resource.ResourceState[source]¶
+

State of a Resource Manager

+
+
+DISCOVERED = 1¶
+
+ +
+
+FAILED = 7¶
+
+ +
+
+NEW = 0¶
+
+ +
+
+PROVISIONED = 3¶
+
+ +
+
+READY = 4¶
+
+ +
+
+RELEASED = 8¶
+
+ +
+
+RESERVED = 2¶
+
+ +
+
+STARTED = 5¶
+
+ +
+
+STOPPED = 6¶
+
+ +
+ +
+
+nepi.execution.resource.clsinit(cls)[source]¶
+

Initializes template information (i.e. attributes and traces) +on classes derived from the ResourceManager class.

+

It is used as a decorator in the class declaration as follows:

+
+

@clsinit +class MyResourceManager(ResourceManager):

+
+
...
+
+
+ +
+
+nepi.execution.resource.clsinit_copy(cls)[source]¶
+

Initializes template information (i.e. attributes and traces) +on classes derived from the ResourceManager class. +It differs from the clsinit method in that it forces inheritance +of attributes and traces from the parent class.

+

It is used as a decorator in the class declaration as follows:

+
+

@clsinit +class MyResourceManager(ResourceManager):

+
+
...
+
+

clsinit_copy should be prefered to clsinit when creating new +ResourceManager child classes.

+
+ +
+
+nepi.execution.resource.failtrap(func)[source]¶
+

Decorator function for instance methods that should set the +RM state to FAILED when an error is raised. The methods that must be +decorated are: discover, reserved, provision, deploy, start, stop.

+
+ +
+
+nepi.execution.resource.find_types()[source]¶
+

Look into the different folders to find all the +availables Resources Managers

+
+ +
+
+nepi.execution.resource.populate_factory()[source]¶
+

Find and rgister all available RMs

+
+ +
+
+

nepi.execution.runner module¶

+
+
+class nepi.execution.runner.ExperimentRunner[source]¶
+

Bases: object

+

The ExperimentRunner entity is responsible of +re-running an experiment described by an ExperimentController +multiple time

+
+
+evaluate_normal_convergence(ec, run, metrics)[source]¶
+

Returns True when the confidence interval of the sample mean is +less than 5% of the mean value, for a 95% confidence level, +assuming normal distribution of the data

+
+ +
+
+run(ec, min_runs=1, max_runs=-1, wait_time=0, wait_guids=[], compute_metric_callback=None, evaluate_convergence_callback=None)[source]¶
+

Run a same experiment independently multiple times, until the +evaluate_convergence_callback function returns True

+ +++ + + + +
Parameters:
    +
  • ec (ExperimentController) – Description of experiment to replicate. +The runner takes care of deploying the EC, so ec.deploy() +must not be invoked directly before or after invoking +runner.run().
  • +
  • min_runs (int) – Minimum number of times the experiment must be +replicated
  • +
  • max_runs (int) – Maximum number of times the experiment can be +replicated
  • +
  • wait_time (float) – Time to wait in seconds on each run between invoking +ec.deploy() and ec.release().
  • +
  • wait_guids (list) – List of guids wait for finalization on each run. +This list is passed to ec.wait_finished()
  • +
  • compute_metric_callback (function) –

    User defined function invoked after +each experiment run to compute a metric. The metric is usually +a network measurement obtained from the data collected +during experiment execution. +The function is invoked passing the ec and the run number as arguments. +It must return the value for the computed metric(s) (usually a single +numerical value, but it can be several).

    +
    +
    metric = compute_metric_callback(ec, run)
    +
  • +
  • evaluate_convergence_callback (function) –

    User defined function invoked after +computing the metric on each run, to evaluate the experiment was +run enough times. It takes the list of cumulated metrics produced by +the compute_metric_callback up to the current run, and decided +whether the metrics have statistically converged to a meaningful value +or not. It must return either True or False.

    +
    +
    stop = evaluate_convergence_callback(ec, run, metrics)
    +

    If stop is True, then the runner will exit.

    +
  • +
+
+
+ +
+
+run_experiment(filepath, wait_time, wait_guids)[source]¶
+

Run an experiment based on the description stored +in filepath.

+
+ +
+ +
+
+

nepi.execution.scheduler module¶

+
+
+class nepi.execution.scheduler.HeapScheduler[source]¶
+

Bases: object

+

Create a Heap Scheduler

+
+

Note

+

This class is thread safe. +All calls to C Extensions are made atomic by the GIL in the CPython implementation. +heapq.heappush, heapq.heappop, and list access are therefore thread-safe.

+
+
+
+next()[source]¶
+

Get the next task in the queue by timestamp and arrival order

+
+ +
+
+pending[source]¶
+

Returns the list of pending task ids

+
+ +
+
+remove(tid)[source]¶
+

Remove a task form the queue

+ +++ + + + +
Parameters:tid (int) – Id of the task to be removed
+
+ +
+
+schedule(task)[source]¶
+

Add a task to the queue ordered by task.timestamp and arrival order

+ +++ + + + +
Parameters:task (task) – task to schedule
+
+ +
+ +
+
+class nepi.execution.scheduler.Task(timestamp, callback)[source]¶
+

Bases: object

+

A Task represents an operation to be executed by the +ExperimentController scheduler

+
+ +
+
+class nepi.execution.scheduler.TaskStatus[source]¶
+

Execution state of the Task

+
+
+DONE = 1¶
+
+ +
+
+ERROR = 2¶
+
+ +
+
+NEW = 0¶
+
+ +
+ +
+
+

nepi.execution.tags module¶

+
+
+

nepi.execution.trace module¶

+
+
+class nepi.execution.trace.Trace(name, help, enabled=False)[source]¶
+

Bases: object

+

A Trace represents information about a Resource that can +be collected

+
+
+help[source]¶
+

Returns the help of the trace

+
+ +
+
+name[source]¶
+

Returns the name of the trace

+
+ +
+ +
+
+class nepi.execution.trace.TraceAttr[source]¶
+

A Trace attribute defines information about a Trace that can +be queried

+
+
+ALL = 'all'¶
+
+ +
+
+PATH = 'path'¶
+
+ +
+
+SIZE = 'size'¶
+
+ +
+
+STREAM = 'stream'¶
+
+ +
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.html b/doc/sphinx/_build/html/_layout/nepi.html new file mode 100644 index 00000000..a68ddb6f --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.html @@ -0,0 +1,483 @@ + + + + + + + + nepi package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi package¶

+
+

Subpackages¶

+
+ +
+
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.all.html b/doc/sphinx/_build/html/_layout/nepi.resources.all.html new file mode 100644 index 00000000..ec59dd76 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.all.html @@ -0,0 +1,165 @@ + + + + + + + + nepi.resources.all package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.resources.all package¶

+
+

Submodules¶

+
+
+

nepi.resources.all.collector module¶

+
+
+class nepi.resources.all.collector.Collector(ec, guid)[source]¶
+

Bases: nepi.execution.resource.ResourceManager

+

The collector entity is reponsible of collecting traces +of a same type associated to RMs into a local directory.

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • ec (ExperimentController) – The Experiment controller
  • +
  • guid (int) – guid of the RM
  • +
+
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_release()[source]¶
+
+ +
+
+store_path[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.html b/doc/sphinx/_build/html/_layout/nepi.resources.html new file mode 100644 index 00000000..c7c70527 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.html @@ -0,0 +1,409 @@ + + + + + + + + nepi.resources package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.resources package¶

+
+

Subpackages¶

+
+ +
+
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.ccn.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ccn.html new file mode 100644 index 00000000..82f66eeb --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ccn.html @@ -0,0 +1,446 @@ + + + + + + + + nepi.resources.linux.ccn package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

nepi.resources.linux.ccn package¶

+
+

Submodules¶

+
+
+

nepi.resources.linux.ccn.ccnapplication module¶

+
+
+class nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+ccnd[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ccn.ccncat module¶

+
+
+class nepi.resources.linux.ccn.ccncat.LinuxCCNCat(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ccn.ccncontent module¶

+
+
+class nepi.resources.linux.ccn.ccncontent.LinuxCCNContent(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+ccnd[source]¶
+
+ +
+
+ccnr[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ccn.ccnd module¶

+
+
+class nepi.resources.linux.ccn.ccnd.LinuxCCND(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+path[source]¶
+
+ +
+
+state[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+
+version[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ccn.ccnpeek module¶

+
+
+class nepi.resources.linux.ccn.ccnpeek.LinuxCCNPeek(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ccn.ccnping module¶

+
+
+class nepi.resources.linux.ccn.ccnping.LinuxCCNPing(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer

+
+
+ccnpingserver[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ccn.ccnpingserver module¶

+
+
+class nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ccn.ccnpoke module¶

+
+
+class nepi.resources.linux.ccn.ccnpoke.LinuxCCNPoke(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ccn.ccnr module¶

+
+
+class nepi.resources.linux.ccn.ccnr.LinuxCCNR(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+ccnd[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ccn.fibentry module¶

+
+
+class nepi.resources.linux.ccn.fibentry.LinuxFIBEntry(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+ccnd[source]¶
+
+ +
+
+configure()[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+ping[source]¶
+
+ +
+
+trace(name, attr='all', block=512, offset=0)[source]¶
+
+ +
+
+traceroute[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.html new file mode 100644 index 00000000..08ed22a6 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.html @@ -0,0 +1,1539 @@ + + + + + + + + nepi.resources.linux package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

nepi.resources.linux package¶

+
+

Subpackages¶

+
+ +
+
+
+

Submodules¶

+
+
+

nepi.resources.linux.application module¶

+
+
+class nepi.resources.linux.application.LinuxApplication(ec, guid)[source]¶
+

Bases: nepi.execution.resource.ResourceManager

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • ec (ExperimentController) – The Experiment controller
  • +
  • guid (int) – guid of the RM
  • +
+
+
+ +
+

Note

+

A LinuxApplication RM represents a process that can be executed in +a remote Linux host using SSH.

+

The LinuxApplication RM takes care of uploadin sources and any files +needed to run the experiment, to the remote host. +It also allows to provide source compilation (build) and installation +instructions, and takes care of automating the sources build and +installation tasks for the user.

+

It is important to note that files uploaded to the remote host have +two possible scopes: single-experiment or multi-experiment. +Single experiment files are those that will not be re-used by other +experiments. Multi-experiment files are those that will. +Sources and shared files are always made available to all experiments.

+

Directory structure:

+

The directory structure used by LinuxApplication RM at the Linux +host is the following:

+
+
${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/nepi-exp –> Base directory for single-experiment files
+
+

+
+
+
${EXP_HOME} |- /<exp-id> –> Base directory for experiment exp-id
+
+

+
+
+
${APP_HOME} |- /<app-guid> –> Base directory for application
+
+
specific files (e.g. command.sh, input)
+

+
+
+
+

${RUN_HOME} |- /<run-id> –> Base directory for run specific

+
+
+
+app_home[source]¶
+
+ +
+
+build(build=None)[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_release()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+

Stops application execution

+
+ +
+
+execute_command(command, env=None, sudo=False, tty=False, forward_x11=False, blocking=False)[source]¶
+
+ +
+
+execute_deploy_command(command, prefix='deploy')[source]¶
+
+ +
+
+in_foreground[source]¶
+

Returns True if the command needs to be executed in foreground. +This means that command will be executed using ‘execute’ instead of +‘run’ (‘run’ executes a command in background and detached from the +terminal)

+

When using X11 forwarding option, the command can not run in background +and detached from a terminal, since we need to keep the terminal attached +to interact with it.

+
+ +
+
+install(install=None)[source]¶
+
+ +
+
+install_dependencies(depends=None)[source]¶
+
+ +
+
+log_message(msg)[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+pid[source]¶
+
+ +
+
+ppid[source]¶
+
+ +
+
+replace_paths(command, node=None, app_home=None, run_home=None)[source]¶
+

Replace all special path tags with shell-escaped actual paths.

+
+ +
+
+run_home[source]¶
+
+ +
+
+state[source]¶
+

Returns the state of the application

+
+ +
+
+trace(name, attr='all', block=512, offset=0)[source]¶
+
+ +
+
+trace_filepath(filename)[source]¶
+
+ +
+
+upload_binaries(bins=None)[source]¶
+
+ +
+
+upload_code(code=None)[source]¶
+
+ +
+
+upload_files(files=None)[source]¶
+
+ +
+
+upload_libraries(libs=None)[source]¶
+
+ +
+
+upload_sources(sources=None, src_dir=None)[source]¶
+
+ +
+
+upload_start_command(overwrite=False)[source]¶
+
+ +
+
+upload_stdin(stdin=None)[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.channel module¶

+
+
+class nepi.resources.linux.channel.LinuxChannel(ec, guid)[source]¶
+

Bases: nepi.execution.resource.ResourceManager

+
+
+log_message(msg)[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.debfuncs module¶

+
+
+nepi.resources.linux.debfuncs.install_packages_command(os, packages)[source]¶
+
+ +
+
+nepi.resources.linux.debfuncs.remove_packages_command(os, packages)[source]¶
+
+ +
+
+

nepi.resources.linux.gretunnel module¶

+
+
+class nepi.resources.linux.gretunnel.LinuxGRETunnel(ec, guid)[source]¶
+

Bases: nepi.resources.linux.tunnel.LinuxTunnel

+
+
+check_state_connection()[source]¶
+
+ +
+
+establish_connection(endpoint, remote_endpoint, data)[source]¶
+
+ +
+
+get_endpoints()[source]¶
+

Returns the list of RM that are endpoints to the tunnel

+
+ +
+
+initiate_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+log_message(msg)[source]¶
+
+ +
+
+terminate_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+
+verify_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.interface module¶

+
+
+class nepi.resources.linux.interface.LinuxInterface(ec, guid)[source]¶
+

Bases: nepi.execution.resource.ResourceManager

+
+
+add_set_hooks()[source]¶
+
+ +
+
+channel[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_discover()[source]¶
+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_release()[source]¶
+
+ +
+
+load_configuration(devname, mac, ip4, mask4, ip6, mask6, mtu, up)[source]¶
+
+ +
+
+log_message(msg)[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+set_hook_mtu(oldval, newval)[source]¶
+
+ +
+
+set_hook_up(oldval, newval)[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.mtr module¶

+
+
+class nepi.resources.linux.mtr.LinuxMtr(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.node module¶

+
+
+class nepi.resources.linux.node.ExitCode[source]¶
+

Error codes that the rexitcode function can return if unable to +check the exit code of a spawned process

+
+
+CORRUPTFILE = -2¶
+
+ +
+
+ERROR = -3¶
+
+ +
+
+FILENOTFOUND = -1¶
+
+ +
+
+OK = 0¶
+
+ +
+ +
+
+class nepi.resources.linux.node.LinuxNode(ec, guid)[source]¶
+

Bases: nepi.execution.resource.ResourceManager

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • ec (ExperimentController) – The Experiment controller
  • +
  • guid (int) – guid of the RM
  • +
+
+
+ +
+

Note

+

There are different ways in which commands can be executed using the +LinuxNode interface (i.e. ‘execute’ - blocking and non blocking, ‘run’, +‘run_and_wait’).

+

Brief explanation:

+
+
    +
  • ‘execute’ (blocking mode) :

    +
    +

    HOW IT WORKS: ‘execute’, forks a process and run the +command, synchronously, attached to the terminal, in +foreground. +The execute method will block until the command returns +the result on ‘out’, ‘err’ (so until it finishes executing).

    +

    USAGE: short-lived commands that must be executed attached +to a terminal and in foreground, for which it IS necessary +to block until the command has finished (e.g. if you want +to run ‘ls’ or ‘cat’).

    +
    +
  • +
  • ‘execute’ (NON blocking mode - blocking = False) :

    +
    +

    HOW IT WORKS: Same as before, except that execute method +will return immediately (even if command still running).

    +

    USAGE: long-lived commands that must be executed attached +to a terminal and in foreground, but for which it is not +necessary to block until the command has finished. (e.g. +start an application using X11 forwarding)

    +
    +
  • +
+
+
    +
  • ‘run’ :

    +
    +

    HOW IT WORKS: Connects to the host ( using SSH if remote) +and launches the command in background, detached from any +terminal (daemonized), and returns. The command continues to +run remotely, but since it is detached from the terminal, +its pipes (stdin, stdout, stderr) can’t be redirected to the +console (as normal non detached processes would), and so they +are explicitly redirected to files. The pidfile is created as +part of the process of launching the command. The pidfile +holds the pid and ppid of the process forked in background, +so later on it is possible to check whether the command is still +running.

    +
    +

    USAGE: long-lived commands that can run detached in background, +for which it is NOT necessary to block (wait) until the command +has finished. (e.g. start an application that is not using X11 +forwarding. It can run detached and remotely in background)

    +
    +
    +
  • +
  • ‘run_and_wait’ :

    +
    +

    HOW IT WORKS: Similar to ‘run’ except that it ‘blocks’ until +the command has finished execution. It also checks whether +errors occurred during runtime by reading the exitcode file, +which contains the exit code of the command that was run +(checking stderr only is not always reliable since many +commands throw debugging info to stderr and the only way to +automatically know whether an error really happened is to +check the process exit code).

    +

    Another difference with respect to ‘run’, is that instead +of directly executing the command as a bash command line, +it uploads the command to a bash script and runs the script. +This allows to use the bash script to debug errors, since +it remains at the remote host and can be run manually to +reproduce the error.

    +

    USAGE: medium-lived commands that can run detached in +background, for which it IS necessary to block (wait) until +the command has finished. (e.g. Package installation, +source compilation, file download, etc)

    +
    +
  • +
+
+
+
+
+
+bin_dir[source]¶
+
+ +
+
+check_errors(home, ecodefile='exitcode', stderr='stderr')[source]¶
+

Checks whether errors occurred while running a command. +It first checks the exit code for the command, and only if the +exit code is an error one it returns the error output.

+
+ +
+
+check_output(home, filename)[source]¶
+

Retrives content of file

+
+ +
+
+clean_experiment()[source]¶
+

Cleans all experiment related files in the Linux host. +It preserves NEPI files and folders that have a multi experiment +scope.

+
+ +
+
+clean_home()[source]¶
+

Cleans all NEPI related folders in the Linux host

+
+ +
+
+clean_processes()[source]¶
+
+ +
+
+copy(src, dst)[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_release()[source]¶
+
+ +
+
+download(src, dst, raise_on_error=True)[source]¶
+
+ +
+
+execute(command, sudo=False, env=None, tty=False, forward_x11=False, retry=3, connect_timeout=30, strict_host_checking=False, persistent=True, blocking=True, with_lock=False)[source]¶
+

Notice that this invocation will block until the +execution finishes. If this is not the desired behavior, +use ‘run’ instead.

+
+ +
+
+exitcode(home, ecodefile='exitcode')[source]¶
+

Get the exit code of an application. +Returns an integer value with the exit code

+
+ +
+
+exp_dir[source]¶
+
+ +
+
+exp_home[source]¶
+
+ +
+
+filter_existing_files(src, dst)[source]¶
+

Removes files that already exist in the Linux host from src list

+
+ +
+
+find_home()[source]¶
+

Retrieves host home directory

+
+ +
+
+format_environment(env, inline=False)[source]¶
+
+
Formats the environment variables for a command to be executed
+
+
either as an inline command +(i.e. export PYTHONPATH=src/..; export LALAL= ..;python script.py) or +as a bash script (i.e. export PYTHONPATH=src/..
+

export LALA=..

+
+
+

)

+
+ +
+
+get_os()[source]¶
+
+ +
+
+getpid(home, pidfile='pidfile')[source]¶
+
+ +
+
+home_dir[source]¶
+
+ +
+
+install_packages(packages, home, run_home=None, raise_on_error=True)[source]¶
+

Install packages in the Linux host.

+

‘home’ is the directory to upload the package installation script. +‘run_home’ is the directory from where to execute the script.

+
+ +
+
+install_packages_command(packages)[source]¶
+
+ +
+
+is_alive()[source]¶
+

Checks if host is responsive

+
+ +
+
+kill(pid, ppid, sudo=False)[source]¶
+
+ +
+
+lib_dir[source]¶
+
+ +
+
+localhost[source]¶
+
+ +
+
+log_message(msg)[source]¶
+
+ +
+
+mkdir(paths, clean=False)[source]¶
+

Paths is either a single remote directory path to create, +or a list of directories to create.

+
+ +
+
+nepi_home[source]¶
+
+ +
+
+node_home[source]¶
+
+ +
+
+os[source]¶
+
+ +
+
+remove_packages(packages, home, run_home=None, raise_on_error=True)[source]¶
+

Uninstall packages from the Linux host.

+

‘home’ is the directory to upload the package un-installation script. +‘run_home’ is the directory from where to execute the script.

+
+ +
+
+rmdir(paths)[source]¶
+

Paths is either a single remote directory path to delete, +or a list of directories to delete.

+
+ +
+
+run(command, home, create_home=False, pidfile='pidfile', stdin=None, stdout='stdout', stderr='stderr', sudo=False, tty=False, strict_host_checking=False)[source]¶
+
+ +
+
+run_and_wait(command, home, shfile='cmd.sh', env=None, overwrite=True, wait_run=True, pidfile='pidfile', ecodefile='exitcode', stdin=None, stdout='stdout', stderr='stderr', sudo=False, tty=False, raise_on_error=True)[source]¶
+

Uploads the ‘command’ to a bash script in the host. +Then runs the script detached in background in the host, and +busy-waites until the script finishes executing.

+
+ +
+
+run_home[source]¶
+
+ +
+
+share_dir[source]¶
+
+ +
+
+src_dir[source]¶
+
+ +
+
+status(pid, ppid)[source]¶
+
+ +
+
+upload(src, dst, text=False, overwrite=True, raise_on_error=True)[source]¶
+

Copy content to destination

+
+
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 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

+
+ +
+
+upload_command(command, shfile='cmd.sh', ecodefile='exitcode', overwrite=True, env=None)[source]¶
+

Saves the command as a bash script file in the remote host, and +forces to save the exit code of the command execution to the ecodefile

+
+ +
+
+use_deb[source]¶
+
+ +
+
+use_rpm[source]¶
+
+ +
+
+usr_dir[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+
+wait_pid(home, pidfile='pidfile', raise_on_error=False)[source]¶
+

Waits until the pid file for the command is generated, +and returns the pid and ppid of the process

+
+ +
+
+wait_run(pid, ppid, trial=0)[source]¶
+

wait for a remote process to finish execution

+
+ +
+ +
+
+class nepi.resources.linux.node.OSType[source]¶
+

Supported flavors of Linux OS

+
+
+DEBIAN = 1¶
+
+ +
+
+FEDORA = 4¶
+
+ +
+
+FEDORA_12 = 20¶
+
+ +
+
+FEDORA_14 = 36¶
+
+ +
+
+FEDORA_8 = 12¶
+
+ +
+
+UBUNTU = 2¶
+
+ +
+ +
+
+

nepi.resources.linux.nping module¶

+
+
+class nepi.resources.linux.nping.LinuxNPing(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ping module¶

+
+
+class nepi.resources.linux.ping.LinuxPing(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.route module¶

+
+
+class nepi.resources.linux.route.LinuxRoute(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+device[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+upload_sources()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.rpmfuncs module¶

+
+
+nepi.resources.linux.rpmfuncs.install_packages_command(os, packages)[source]¶
+
+ +
+
+nepi.resources.linux.rpmfuncs.install_rpmfusion_command(os)[source]¶
+
+ +
+
+nepi.resources.linux.rpmfuncs.remove_packages_command(os, packages)[source]¶
+
+ +
+
+

nepi.resources.linux.tap module¶

+
+
+class nepi.resources.linux.tap.LinuxTap(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+IFF_TAP = 2¶
+
+ +
+
+IFF_TUN = 1¶
+
+ +
+
+check_status()[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_release()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+establish_udp_connection(remote_endpoint, connection_app_home, connection_run_home, port)[source]¶
+
+ +
+
+gre_connect(remote_endpoint, connection_app_home, connection_run_home)[source]¶
+
+ +
+
+gre_enabled[source]¶
+
+ +
+
+initiate_udp_connection(remote_endpoint, connection_app_home, connection_run_home, cipher, cipher_key, bwlimit, txqueuelen)[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+sock_name[source]¶
+
+ +
+
+state[source]¶
+
+ +
+
+terminate_connection(remote_endpoint, connection_app_home, connection_run_home)[source]¶
+
+ +
+
+udp_connect(remote_endpoint, connection_app_home, connection_run_home, cipher, cipher_key, bwlimit, txqueuelen)[source]¶
+
+ +
+
+upload_sources()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+
+verify_connection(remote_endpoint, connection_app_home, connection_run_home)[source]¶
+
+ +
+
+vif_prefix[source]¶
+
+ +
+
+vif_type[source]¶
+
+ +
+
+vif_type_flag[source]¶
+
+ +
+
+wait_file(home, filename)[source]¶
+

Waits until file on endpoint is generated

+
+ +
+ +
+
+

nepi.resources.linux.tcpdump module¶

+
+
+class nepi.resources.linux.tcpdump.LinuxTcpdump(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.traceroute module¶

+
+
+class nepi.resources.linux.traceroute.LinuxTraceroute(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.tun module¶

+
+
+class nepi.resources.linux.tun.LinuxTun(ec, guid)[source]¶
+

Bases: nepi.resources.linux.tap.LinuxTap

+
+ +
+
+

nepi.resources.linux.tunnel module¶

+
+
+class nepi.resources.linux.tunnel.LinuxTunnel(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+app_home(endpoint)[source]¶
+
+ +
+
+check_state_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+

Stops application execution

+
+ +
+
+endpoint1[source]¶
+
+ +
+
+endpoint2[source]¶
+
+ +
+
+endpoint_mkdir(endpoint)[source]¶
+
+ +
+
+establish_connection(endpoint, remote_endpoint, data)[source]¶
+
+ +
+
+get_endpoints()[source]¶
+

Returns the list of RM that are endpoints to the tunnel

+
+ +
+
+initiate_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+log_message(msg)[source]¶
+
+ +
+
+run_home(endpoint)[source]¶
+
+ +
+
+state[source]¶
+

Returns the state of the application

+
+ +
+
+terminate_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+
+verify_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.udptest module¶

+
+
+class nepi.resources.linux.udptest.LinuxUdpTest(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+

Uses the hpcbench udptest tool to gather UDP measurements. +Measurements require two ends, a server and a client RM.

+

http://hpcbench.sourceforge.net/

+
+
+do_deploy()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.udptunnel module¶

+
+
+class nepi.resources.linux.udptunnel.LinuxUdpTunnel(ec, guid)[source]¶
+

Bases: nepi.resources.linux.tunnel.LinuxTunnel

+
+
+check_state_connection()[source]¶
+
+ +
+
+establish_connection(endpoint, remote_endpoint, port)[source]¶
+
+ +
+
+get_endpoints()[source]¶
+

Returns the list of RM that are endpoints to the tunnel

+
+ +
+
+initiate_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+log_message(msg)[source]¶
+
+ +
+
+terminate_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+verify_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.netns.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.netns.html new file mode 100644 index 00000000..1a34b535 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.netns.html @@ -0,0 +1,285 @@ + + + + + + + + nepi.resources.linux.netns package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.resources.linux.netns package¶

+
+

Submodules¶

+
+
+

nepi.resources.linux.netns.netnsclient module¶

+
+
+class nepi.resources.linux.netns.netnsclient.LinuxNetNSClient(emulation)[source]¶
+

Bases: nepi.resources.netns.netnsclient.NetNSClient

+
+
+create(*args, **kwargs)[source]¶
+
+ +
+
+emulation[source]¶
+
+ +
+
+flush(*args, **kwargs)[source]¶
+
+ +
+
+get(*args, **kwargs)[source]¶
+
+ +
+
+invoke(*args, **kwargs)[source]¶
+
+ +
+
+send_msg(msg_type, *args, **kwargs)[source]¶
+
+ +
+
+set(*args, **kwargs)[source]¶
+
+ +
+
+shutdown(*args, **kwargs)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.netns.netnsemulation module¶

+
+
+class nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication, nepi.resources.netns.netnsemulation.NetNSEmulation

+
+
+clone_command(name, repo, src)[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_release()[source]¶
+
+ +
+
+do_start()[source]¶
+

Starts execution execution

+
+ +
+
+do_stop()[source]¶
+

Stops simulation execution

+
+ +
+
+netns_repo[source]¶
+
+ +
+
+netns_src[source]¶
+
+ +
+
+netns_version[source]¶
+
+ +
+
+python_passfd_repo[source]¶
+
+ +
+
+python_passfd_src[source]¶
+
+ +
+
+python_passfd_version[source]¶
+
+ +
+
+python_unshare_repo[source]¶
+
+ +
+
+python_unshare_src[source]¶
+
+ +
+
+python_unshare_version[source]¶
+
+ +
+
+remote_socket[source]¶
+
+ +
+
+replace_paths(command)[source]¶
+

Replace all special path tags with shell-escaped actual paths.

+
+ +
+
+socket_name[source]¶
+
+ +
+
+upload_extra_sources(sources=None, src_dir=None)[source]¶
+
+ +
+
+upload_sources()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+
+wait_remote_socket()[source]¶
+

Waits until the remote socket is created

+
+ +
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.ccn.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.ccn.html new file mode 100644 index 00000000..5098df24 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.ccn.html @@ -0,0 +1,186 @@ + + + + + + + + nepi.resources.linux.ns3.ccn package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

nepi.resources.linux.ns3.ccn package¶

+
+

Submodules¶

+
+
+

nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication module¶

+
+
+class nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication.LinuxNS3DceCCNCat(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

+
+ +
+
+

nepi.resources.linux.ns3.ccn.ns3ccndceapplication module¶

+
+
+class nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication

+
+ +
+
+

nepi.resources.linux.ns3.ccn.ns3ccnddceapplication module¶

+
+
+class nepi.resources.linux.ns3.ccn.ns3ccnddceapplication.LinuxNS3DceCCND(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

+
+
+version[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication module¶

+
+
+class nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication.LinuxNS3DceCCNPeek(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

+
+ +
+
+

nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication module¶

+
+
+class nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication.LinuxNS3DceCCNPoke(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

+
+ +
+
+

nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication module¶

+
+
+class nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication.LinuxNS3DceCCNR(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

+
+ +
+
+

nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication module¶

+
+
+class nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication.LinuxNS3DceFIBEntry(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ns3.ccn.ns3ccndceapplication.LinuxNS3CCNDceApplication

+
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.html b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.html new file mode 100644 index 00000000..9f1cc83c --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.linux.ns3.html @@ -0,0 +1,536 @@ + + + + + + + + nepi.resources.linux.ns3 package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

nepi.resources.linux.ns3 package¶

+ +
+

Submodules¶

+
+
+

nepi.resources.linux.ns3.fdudptunnel module¶

+
+
+class nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel(ec, guid)[source]¶
+

Bases: nepi.resources.linux.udptunnel.LinuxUdpTunnel

+
+
+app_home(endpoint)[source]¶
+
+ +
+
+check_state_connection()[source]¶
+
+ +
+
+endpoint1[source]¶
+
+ +
+
+endpoint2[source]¶
+
+ +
+
+endpoint_mkdir(endpoint)[source]¶
+
+ +
+
+endpoint_node(endpoint)[source]¶
+
+ +
+
+establish(endpoint, remote_endpoint, port)[source]¶
+
+ +
+
+establish_connection(endpoint, remote_endpoint, port)[source]¶
+
+ +
+
+get_endpoints()[source]¶
+

Returns the list of RM that are endpoints to the tunnel

+
+ +
+
+initiate(endpoint, remote_endpoint, address, cipher, cipher_key, bwlimit, txqueuelen)[source]¶
+
+ +
+
+initiate_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+log_message(msg)[source]¶
+
+ +
+
+node1[source]¶
+
+ +
+
+node2[source]¶
+
+ +
+
+pi[source]¶
+
+ +
+
+run_home(endpoint)[source]¶
+
+ +
+
+terminate_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+upload_sources(endpoint)[source]¶
+
+ +
+
+verify(endpoint)[source]¶
+
+ +
+
+verify_connection(endpoint, remote_endpoint)[source]¶
+
+ +
+
+wait_file(endpoint, filename)[source]¶
+

Waits until file on endpoint is generated

+
+ +
+
+wait_local_port(endpoint)[source]¶
+

Waits until the local_port file for the endpoint is generated, +and returns the port number

+
+ +
+
+wait_result(endpoint)[source]¶
+

Waits until the return code file for the endpoint is generated

+
+ +
+ +
+
+

nepi.resources.linux.ns3.ns3client module¶

+
+
+class nepi.resources.linux.ns3.ns3client.LinuxNS3Client(simulation)[source]¶
+

Bases: nepi.resources.ns3.ns3client.NS3Client

+
+
+create(*args, **kwargs)[source]¶
+
+ +
+
+factory(*args, **kwargs)[source]¶
+
+ +
+
+flush(*args, **kwargs)[source]¶
+
+ +
+
+get(*args, **kwargs)[source]¶
+
+ +
+
+invoke(*args, **kwargs)[source]¶
+
+ +
+
+send_msg(msg_type, *args, **kwargs)[source]¶
+
+ +
+
+set(*args, **kwargs)[source]¶
+
+ +
+
+shutdown(*args, **kwargs)[source]¶
+
+ +
+
+simulation[source]¶
+
+ +
+
+start(*args, **kwargs)[source]¶
+
+ +
+
+stop(*args, **kwargs)[source]¶
+
+ +
+ +
+
+

nepi.resources.linux.ns3.ns3dceapplication module¶

+
+
+class nepi.resources.linux.ns3.ns3dceapplication.LinuxNS3DceApplication(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication

+
+ +
+
+

nepi.resources.linux.ns3.ns3pingdceapplication module¶

+
+
+class nepi.resources.linux.ns3.ns3pingdceapplication.LinuxDcePing(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ns3.ns3dceapplication.LinuxNS3DceApplication

+
+ +
+
+

nepi.resources.linux.ns3.ns3simulation module¶

+
+
+class nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication, nepi.resources.ns3.ns3simulation.NS3Simulation

+
+
+configure()[source]¶
+
+ +
+
+dce_helper[source]¶
+
+ +
+
+dce_repo[source]¶
+
+ +
+
+dce_src_location[source]¶
+
+ +
+
+dce_version[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_release()[source]¶
+
+ +
+
+do_start()[source]¶
+

Starts simulation execution

+
+ +
+
+do_stop()[source]¶
+

Stops simulation execution

+
+ +
+
+enable_dce[source]¶
+
+ +
+
+ns3_build_location[source]¶
+
+ +
+
+ns3_repo[source]¶
+
+ +
+
+ns3_src_location[source]¶
+
+ +
+
+pygccxml_version[source]¶
+
+ +
+
+remote_socket[source]¶
+
+ +
+
+replace_paths(command)[source]¶
+

Replace all special path tags with shell-escaped actual paths.

+
+ +
+
+socket_name[source]¶
+
+ +
+
+state[source]¶
+
+ +
+
+trace(name, attr='all', block=512, offset=0)[source]¶
+
+ +
+
+upload_extra_sources(sources=None, src_dir=None)[source]¶
+
+ +
+
+upload_sources()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+
+wait_remote_socket()[source]¶
+

Waits until the remote socket is created

+
+ +
+ +
+ +
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.netns.html b/doc/sphinx/_build/html/_layout/nepi.resources.netns.html new file mode 100644 index 00000000..6df18f48 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.netns.html @@ -0,0 +1,617 @@ + + + + + + + + nepi.resources.netns package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

nepi.resources.netns package¶

+
+

Submodules¶

+
+
+

nepi.resources.netns.netnsapplication module¶

+
+
+class nepi.resources.netns.netnsapplication.NetNSApplication(ec, guid)[source]¶
+

Bases: nepi.resources.netns.netnsbase.NetNSBase

+
+
+do_start()[source]¶
+
+ +
+
+emulation[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+state[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnsbase module¶

+
+
+class nepi.resources.netns.netnsbase.NetNSBase(ec, guid)[source]¶
+

Bases: nepi.execution.resource.ResourceManager

+
+
+connected[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+get(name)[source]¶
+
+ +
+
+set(name, value)[source]¶
+
+ +
+
+state[source]¶
+
+ +
+
+trace(name, attr='all', block=512, offset=0)[source]¶
+
+ +
+
+uuid[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnsclient module¶

+
+
+class nepi.resources.netns.netnsclient.NetNSClient[source]¶
+

Bases: object

+

Common Interface for NS3 client classes

+
+
+create(*args, **kwargs)[source]¶
+
+ +
+
+flush(*args, **kwargs)[source]¶
+
+ +
+
+get(*args, **kwargs)[source]¶
+
+ +
+
+invoke(*args, **kwargs)[source]¶
+
+ +
+
+set(*args, **kwargs)[source]¶
+
+ +
+
+shutdown(*args, **kwargs)[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnsemulation module¶

+
+
+class nepi.resources.netns.netnsemulation.NetNSEmulation[source]¶
+

Bases: object

+
+
+client[source]¶
+
+ +
+
+create(*args, **kwargs)[source]¶
+
+ +
+
+emu_get(*args, **kwargs)[source]¶
+
+ +
+
+emu_set(*args, **kwargs)[source]¶
+
+ +
+
+flush(*args, **kwargs)[source]¶
+
+ +
+
+invoke(*args, **kwargs)[source]¶
+
+ +
+
+shutdown(*args, **kwargs)[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnsinterface module¶

+
+
+class nepi.resources.netns.netnsinterface.NetNSInterface(ec, guid)[source]¶
+

Bases: nepi.resources.netns.netnsbase.NetNSBase

+
+ +
+
+

nepi.resources.netns.netnsipv4address module¶

+
+
+class nepi.resources.netns.netnsipv4address.NetNSIPv4Address(ec, guid)[source]¶
+

Bases: nepi.resources.netns.netnsbase.NetNSBase

+
+
+emulation[source]¶
+
+ +
+
+interface[source]¶
+
+ +
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnsnode module¶

+
+
+class nepi.resources.netns.netnsnode.NetNSNode(ec, guid)[source]¶
+

Bases: nepi.resources.netns.netnsbase.NetNSBase

+
+
+emulation[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnsnodeinterface module¶

+
+
+class nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface(ec, guid)[source]¶
+

Bases: nepi.resources.netns.netnsinterface.NetNSInterface

+
+
+emulation[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+switch[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnsroute module¶

+
+
+class nepi.resources.netns.netnsroute.NetNSIPv4Route(ec, guid)[source]¶
+

Bases: nepi.resources.netns.netnsbase.NetNSBase

+
+
+emulation[source]¶
+
+ +
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnsserver module¶

+
+
+class nepi.resources.netns.netnsserver.NetNSWrapperMessage[source]¶
+
+
+CREATE = 'CREATE'¶
+
+ +
+
+FLUSH = 'FLUSH'¶
+
+ +
+
+GET = 'GET'¶
+
+ +
+
+INVOKE = 'INVOKE'¶
+
+ +
+
+SET = 'SET'¶
+
+ +
+
+SHUTDOWN = 'SHUTDOWN'¶
+
+ +
+ +
+
+nepi.resources.netns.netnsserver.create_socket(socket_name)[source]¶
+
+ +
+
+nepi.resources.netns.netnsserver.get_options()[source]¶
+
+ +
+
+nepi.resources.netns.netnsserver.handle_message(wrapper, msg_type, args, kwargs)[source]¶
+
+ +
+
+nepi.resources.netns.netnsserver.recv_msg(conn)[source]¶
+
+ +
+
+nepi.resources.netns.netnsserver.run_server(socket_name, level=20, enable_dump=False)[source]¶
+
+ +
+
+nepi.resources.netns.netnsserver.send_reply(conn, reply)[source]¶
+
+ +
+
+

nepi.resources.netns.netnsswitch module¶

+
+
+class nepi.resources.netns.netnsswitch.NetNSSwitch(ec, guid)[source]¶
+

Bases: nepi.resources.netns.netnsbase.NetNSBase

+
+
+emulation[source]¶
+
+ +
+
+interface[source]¶
+
+ +
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnswrapper module¶

+
+
+class nepi.resources.netns.netnswrapper.NetNSWrapper(loglevel=20, enable_dump=False)[source]¶
+

Bases: object

+
+
+create(clazzname, *args)[source]¶
+

This method should be used to construct netns objects

+
+ +
+
+debuger[source]¶
+
+ +
+
+get(uuid, name)[source]¶
+
+ +
+
+get_object(uuid)[source]¶
+
+ +
+
+invoke(uuid, operation, *args, **kwargs)[source]¶
+
+ +
+
+logger[source]¶
+
+ +
+
+make_uuid()[source]¶
+
+ +
+
+replace_args(args)[source]¶
+
+ +
+
+replace_kwargs(kwargs)[source]¶
+
+ +
+
+set(uuid, name, value)[source]¶
+
+ +
+
+shutdown()[source]¶
+
+ +
+ +
+
+

nepi.resources.netns.netnswrapper_debug module¶

+
+
+class nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger(enabled)[source]¶
+

Bases: object

+
+
+dump_create(uuid, clazzname, args)[source]¶
+
+ +
+
+dump_factory(uuid, type_name, kwargs)[source]¶
+
+ +
+
+dump_get(uuid, name)[source]¶
+
+ +
+
+dump_header()[source]¶
+
+ +
+
+dump_invoke(newuuid, uuid, operation, args, kwargs)[source]¶
+
+ +
+
+dump_set(uuid, name, value)[source]¶
+
+ +
+
+dump_shutdown()[source]¶
+
+ +
+
+dump_to_script(command)[source]¶
+
+ +
+
+enabled[source]¶
+
+ +
+
+format_args(args)[source]¶
+
+ +
+
+format_kwargs(kwargs)[source]¶
+
+ +
+
+format_value(value)[source]¶
+
+ +
+
+script_path[source]¶
+
+ +
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.ns3.classes.html b/doc/sphinx/_build/html/_layout/nepi.resources.ns3.classes.html new file mode 100644 index 00000000..38f606a7 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.ns3.classes.html @@ -0,0 +1,1171 @@ + + + + + + + + nepi.resources.ns3.classes package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.resources.ns3.classes package¶

+
+

Submodules¶

+
+
+

nepi.resources.ns3.classes.aarf_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.aarf_wifi_manager.NS3AarfWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.aarfcd_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.aarfcd_wifi_manager.NS3AarfcdWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.adhoc_wifi_mac module¶

+
+
+class nepi.resources.ns3.classes.adhoc_wifi_mac.NS3AdhocWifiMac(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

+
+ +
+
+

nepi.resources.ns3.classes.aloha_noack_net_device module¶

+
+
+class nepi.resources.ns3.classes.aloha_noack_net_device.NS3AlohaNoackNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.amrr_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.amrr_wifi_manager.NS3AmrrWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.ap_wifi_mac module¶

+
+
+class nepi.resources.ns3.classes.ap_wifi_mac.NS3ApWifiMac(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

+
+ +
+
+

nepi.resources.ns3.classes.arf_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.arf_wifi_manager.NS3ArfWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.arp_l3protocol module¶

+
+
+class nepi.resources.ns3.classes.arp_l3protocol.NS3ArpL3Protocol(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3arpl3protocol.NS3BaseArpL3Protocol

+
+ +
+
+

nepi.resources.ns3.classes.base_station_net_device module¶

+
+
+class nepi.resources.ns3.classes.base_station_net_device.NS3BaseStationNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.binary_error_model module¶

+
+
+class nepi.resources.ns3.classes.binary_error_model.NS3BinaryErrorModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

+
+ +
+
+

nepi.resources.ns3.classes.binary_error_sixlow_model module¶

+
+
+class nepi.resources.ns3.classes.binary_error_sixlow_model.NS3BinaryErrorSixlowModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

+
+ +
+
+

nepi.resources.ns3.classes.bridge_channel module¶

+
+
+class nepi.resources.ns3.classes.bridge_channel.NS3BridgeChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.bridge_net_device module¶

+
+
+class nepi.resources.ns3.classes.bridge_net_device.NS3BridgeNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.bulk_send_application module¶

+
+
+class nepi.resources.ns3.classes.bulk_send_application.NS3BulkSendApplication(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.burst_error_model module¶

+
+
+class nepi.resources.ns3.classes.burst_error_model.NS3BurstErrorModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

+
+ +
+
+

nepi.resources.ns3.classes.cara_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.cara_wifi_manager.NS3CaraWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.constant_acceleration_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.constant_acceleration_mobility_model.NS3ConstantAccelerationMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.constant_position_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.constant_position_mobility_model.NS3ConstantPositionMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.constant_rate_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.constant_rate_wifi_manager.NS3ConstantRateWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.constant_speed_propagation_delay_model module¶

+
+
+class nepi.resources.ns3.classes.constant_speed_propagation_delay_model.NS3ConstantSpeedPropagationDelayModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel

+
+ +
+
+

nepi.resources.ns3.classes.constant_velocity_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.constant_velocity_mobility_model.NS3ConstantVelocityMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.cost231propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.cost231propagation_loss_model.NS3Cost231PropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.csma_channel module¶

+
+
+class nepi.resources.ns3.classes.csma_channel.NS3CsmaChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.csma_net_device module¶

+
+
+class nepi.resources.ns3.classes.csma_net_device.NS3CsmaNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.drop_tail_queue module¶

+
+
+class nepi.resources.ns3.classes.drop_tail_queue.NS3DropTailQueue(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3queue.NS3BaseQueue

+
+ +
+
+

nepi.resources.ns3.classes.dsrdsr_routing module¶

+
+
+class nepi.resources.ns3.classes.dsrdsr_routing.NS3dsrDsrRouting(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+ +
+
+

nepi.resources.ns3.classes.emu_net_device module¶

+
+
+class nepi.resources.ns3.classes.emu_net_device.NS3EmuNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.error_channel module¶

+
+
+class nepi.resources.ns3.classes.error_channel.NS3ErrorChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.error_channel_sixlow module¶

+
+
+class nepi.resources.ns3.classes.error_channel_sixlow.NS3ErrorChannelSixlow(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.error_net_device module¶

+
+
+class nepi.resources.ns3.classes.error_net_device.NS3ErrorNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.fd_net_device module¶

+
+
+class nepi.resources.ns3.classes.fd_net_device.NS3FdNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3fdnetdevice.NS3BaseFdNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.fixed_rss_loss_model module¶

+
+
+class nepi.resources.ns3.classes.fixed_rss_loss_model.NS3FixedRssLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.friis_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.friis_propagation_loss_model.NS3FriisPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.gauss_markov_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.gauss_markov_mobility_model.NS3GaussMarkovMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.hierarchical_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.hierarchical_mobility_model.NS3HierarchicalMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model.NS3HybridBuildingsPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.icmpv4l4protocol module¶

+
+
+class nepi.resources.ns3.classes.icmpv4l4protocol.NS3Icmpv4L4Protocol(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3icmpv4l4protocol.NS3BaseIcmpv4L4Protocol

+
+ +
+
+

nepi.resources.ns3.classes.icmpv6l4protocol module¶

+
+
+class nepi.resources.ns3.classes.icmpv6l4protocol.NS3Icmpv6L4Protocol(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+ +
+
+

nepi.resources.ns3.classes.ideal_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.ideal_wifi_manager.NS3IdealWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.ipv4l3protocol module¶

+
+
+class nepi.resources.ns3.classes.ipv4l3protocol.NS3Ipv4L3Protocol(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3ipv4l3protocol.NS3BaseIpv4L3Protocol

+
+ +
+
+

nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model.NS3ItuR1411LosPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model.NS3ItuR1411NlosOverRooftopPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.jakes_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.jakes_propagation_loss_model.NS3JakesPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model.NS3Kun2600MhzPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.list_error_model module¶

+
+
+class nepi.resources.ns3.classes.list_error_model.NS3ListErrorModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

+
+ +
+
+

nepi.resources.ns3.classes.log_distance_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.log_distance_propagation_loss_model.NS3LogDistancePropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.loopback_net_device module¶

+
+
+class nepi.resources.ns3.classes.loopback_net_device.NS3LoopbackNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.lr_wpan_net_device module¶

+
+
+class nepi.resources.ns3.classes.lr_wpan_net_device.NS3LrWpanNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.lte_enb_net_device module¶

+
+
+class nepi.resources.ns3.classes.lte_enb_net_device.NS3LteEnbNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.lte_simple_net_device module¶

+
+
+class nepi.resources.ns3.classes.lte_simple_net_device.NS3LteSimpleNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.lte_ue_net_device module¶

+
+
+class nepi.resources.ns3.classes.lte_ue_net_device.NS3LteUeNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.matrix_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.matrix_propagation_loss_model.NS3MatrixPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.mesh_point_device module¶

+
+
+class nepi.resources.ns3.classes.mesh_point_device.NS3MeshPointDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.mesh_wifi_interface_mac module¶

+
+
+class nepi.resources.ns3.classes.mesh_wifi_interface_mac.NS3MeshWifiInterfaceMac(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

+
+ +
+
+

nepi.resources.ns3.classes.minstrel_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.minstrel_wifi_manager.NS3MinstrelWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.multi_model_spectrum_channel module¶

+
+
+class nepi.resources.ns3.classes.multi_model_spectrum_channel.NS3MultiModelSpectrumChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.nakagami_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.nakagami_propagation_loss_model.NS3NakagamiPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.nist_error_rate_model module¶

+
+
+class nepi.resources.ns3.classes.nist_error_rate_model.NS3NistErrorRateModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel

+
+ +
+
+

nepi.resources.ns3.classes.node module¶

+
+
+class nepi.resources.ns3.classes.node.NS3Node(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3node.NS3BaseNode

+
+ +
+
+

nepi.resources.ns3.classes.non_communicating_net_device module¶

+
+
+class nepi.resources.ns3.classes.non_communicating_net_device.NS3NonCommunicatingNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.ocb_wifi_mac module¶

+
+
+class nepi.resources.ns3.classes.ocb_wifi_mac.NS3OcbWifiMac(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

+
+ +
+
+

nepi.resources.ns3.classes.oh_buildings_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.oh_buildings_propagation_loss_model.NS3OhBuildingsPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.okumura_hata_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.okumura_hata_propagation_loss_model.NS3OkumuraHataPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.on_off_application module¶

+
+
+class nepi.resources.ns3.classes.on_off_application.NS3OnOffApplication(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.onoe_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.onoe_wifi_manager.NS3OnoeWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.packet_sink module¶

+
+
+class nepi.resources.ns3.classes.packet_sink.NS3PacketSink(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.ping6 module¶

+
+
+class nepi.resources.ns3.classes.ping6.NS3Ping6(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.point_to_point_channel module¶

+
+
+class nepi.resources.ns3.classes.point_to_point_channel.NS3PointToPointChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.point_to_point_net_device module¶

+
+
+class nepi.resources.ns3.classes.point_to_point_net_device.NS3PointToPointNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.point_to_point_remote_channel module¶

+
+
+class nepi.resources.ns3.classes.point_to_point_remote_channel.NS3PointToPointRemoteChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.radvd module¶

+
+
+class nepi.resources.ns3.classes.radvd.NS3Radvd(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.random_direction2d_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.random_direction2d_mobility_model.NS3RandomDirection2dMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.random_propagation_delay_model module¶

+
+
+class nepi.resources.ns3.classes.random_propagation_delay_model.NS3RandomPropagationDelayModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel

+
+ +
+
+

nepi.resources.ns3.classes.random_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.random_propagation_loss_model.NS3RandomPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.random_walk2d_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.random_walk2d_mobility_model.NS3RandomWalk2dMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.random_waypoint_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.random_waypoint_mobility_model.NS3RandomWaypointMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.range_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.range_propagation_loss_model.NS3RangePropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.rate_error_model module¶

+
+
+class nepi.resources.ns3.classes.rate_error_model.NS3RateErrorModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

+
+ +
+
+

nepi.resources.ns3.classes.receive_list_error_model module¶

+
+
+class nepi.resources.ns3.classes.receive_list_error_model.NS3ReceiveListErrorModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel

+
+ +
+
+

nepi.resources.ns3.classes.red_queue module¶

+
+
+class nepi.resources.ns3.classes.red_queue.NS3RedQueue(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3queue.NS3BaseQueue

+
+ +
+
+

nepi.resources.ns3.classes.rraa_wifi_manager module¶

+
+
+class nepi.resources.ns3.classes.rraa_wifi_manager.NS3RraaWifiManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager

+
+ +
+
+

nepi.resources.ns3.classes.simple_channel module¶

+
+
+class nepi.resources.ns3.classes.simple_channel.NS3SimpleChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.simple_net_device module¶

+
+
+class nepi.resources.ns3.classes.simple_net_device.NS3SimpleNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.single_model_spectrum_channel module¶

+
+
+class nepi.resources.ns3.classes.single_model_spectrum_channel.NS3SingleModelSpectrumChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.six_low_pan_net_device module¶

+
+
+class nepi.resources.ns3.classes.six_low_pan_net_device.NS3SixLowPanNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.sta_wifi_mac module¶

+
+
+class nepi.resources.ns3.classes.sta_wifi_mac.NS3StaWifiMac(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac

+
+ +
+
+

nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model.NS3SteadyStateRandomWaypointMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.subscriber_station_net_device module¶

+
+
+class nepi.resources.ns3.classes.subscriber_station_net_device.NS3SubscriberStationNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.tap_bridge module¶

+
+
+class nepi.resources.ns3.classes.tap_bridge.NS3TapBridge(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.tcp_l4protocol module¶

+
+
+class nepi.resources.ns3.classes.tcp_l4protocol.NS3TcpL4Protocol(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+ +
+
+

nepi.resources.ns3.classes.three_log_distance_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.three_log_distance_propagation_loss_model.NS3ThreeLogDistancePropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model module¶

+
+
+class nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model.NS3TwoRayGroundPropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel

+
+ +
+
+

nepi.resources.ns3.classes.uan_channel module¶

+
+
+class nepi.resources.ns3.classes.uan_channel.NS3UanChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3channel.NS3BaseChannel

+
+ +
+
+

nepi.resources.ns3.classes.udp_client module¶

+
+
+class nepi.resources.ns3.classes.udp_client.NS3UdpClient(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.udp_echo_client module¶

+
+
+class nepi.resources.ns3.classes.udp_echo_client.NS3UdpEchoClient(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.udp_echo_server module¶

+
+
+class nepi.resources.ns3.classes.udp_echo_server.NS3UdpEchoServer(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.udp_l4protocol module¶

+
+
+class nepi.resources.ns3.classes.udp_l4protocol.NS3UdpL4Protocol(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+ +
+
+

nepi.resources.ns3.classes.udp_server module¶

+
+
+class nepi.resources.ns3.classes.udp_server.NS3UdpServer(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.udp_trace_client module¶

+
+
+class nepi.resources.ns3.classes.udp_trace_client.NS3UdpTraceClient(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.v4ping module¶

+
+
+class nepi.resources.ns3.classes.v4ping.NS3V4Ping(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+ +
+
+

nepi.resources.ns3.classes.virtual_net_device module¶

+
+
+class nepi.resources.ns3.classes.virtual_net_device.NS3VirtualNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.waypoint_mobility_model module¶

+
+
+class nepi.resources.ns3.classes.waypoint_mobility_model.NS3WaypointMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel

+
+ +
+
+

nepi.resources.ns3.classes.wifi_net_device module¶

+
+
+class nepi.resources.ns3.classes.wifi_net_device.NS3WifiNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifinetdevice.NS3BaseWifiNetDevice

+
+ +
+
+

nepi.resources.ns3.classes.yans_error_rate_model module¶

+
+
+class nepi.resources.ns3.classes.yans_error_rate_model.NS3YansErrorRateModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel

+
+ +
+
+

nepi.resources.ns3.classes.yans_wifi_channel module¶

+
+
+class nepi.resources.ns3.classes.yans_wifi_channel.NS3YansWifiChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel

+
+ +
+
+

nepi.resources.ns3.classes.yans_wifi_phy module¶

+
+
+class nepi.resources.ns3.classes.yans_wifi_phy.NS3YansWifiPhy(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy

+
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.ns3.html b/doc/sphinx/_build/html/_layout/nepi.resources.ns3.html new file mode 100644 index 00000000..5add2fcc --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.ns3.html @@ -0,0 +1,1239 @@ + + + + + + + + nepi.resources.ns3 package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.resources.ns3 package¶

+
+

Subpackages¶

+
+ +
+
+
+

Submodules¶

+
+
+

nepi.resources.ns3.ns3application module¶

+
+
+class nepi.resources.ns3.ns3application.NS3BaseApplication(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+state[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3arpl3protocol module¶

+
+
+class nepi.resources.ns3.ns3arpl3protocol.NS3BaseArpL3Protocol(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3base module¶

+
+
+class nepi.resources.ns3.ns3base.NS3Base(ec, guid)[source]¶
+

Bases: nepi.execution.resource.ResourceManager

+
+
+connected[source]¶
+
+ +
+
+do_deploy()[source]¶
+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+get(name)[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+set(name, value)[source]¶
+
+ +
+
+simulation[source]¶
+
+ +
+
+state[source]¶
+
+ +
+
+trace(name, attr='all', block=512, offset=0)[source]¶
+
+ +
+
+uuid[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3ccndceapplication module¶

+
+
+class nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication

+
+
+ccn_client_helper_uuid[source]¶
+
+ +
+
+ccn_client_lock = <thread.lock object at 0x7f0290310f90>¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3channel module¶

+
+
+class nepi.resources.ns3.ns3channel.NS3BaseChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+devices[source]¶
+
+ +
+
+simulation[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3client module¶

+
+
+class nepi.resources.ns3.ns3client.NS3Client[source]¶
+

Bases: object

+

Common Interface for NS3 client classes

+
+
+create(*args, **kwargs)[source]¶
+
+ +
+
+factory(*args, **kwargs)[source]¶
+
+ +
+
+flush(*args, **kwargs)[source]¶
+
+ +
+
+get(*args, **kwargs)[source]¶
+
+ +
+
+invoke(*args, **kwargs)[source]¶
+
+ +
+
+set(*args, **kwargs)[source]¶
+
+ +
+
+shutdown(*args, **kwargs)[source]¶
+
+ +
+
+start(*args, **kwargs)[source]¶
+
+ +
+
+stop(*args, **kwargs)[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3dceapplication module¶

+
+
+class nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3application.NS3BaseApplication

+
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+pid[source]¶
+
+ +
+
+trace(name, attr='all', block=512, offset=0)[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3dcehelper module¶

+
+
+class nepi.resources.ns3.ns3dcehelper.NS3DceHelper(simulation)[source]¶
+

Bases: object

+
+
+dce_application_lock[source]¶
+
+ +
+
+dce_application_uuid[source]¶
+
+ +
+
+dce_manager_lock[source]¶
+
+ +
+
+dce_manager_uuid[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3errormodel module¶

+
+
+class nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+device[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3errorratemodel module¶

+
+
+class nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+node[source]¶
+
+ +
+
+phy[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3fdnetdevice module¶

+
+
+class nepi.resources.ns3.ns3fdnetdevice.NS3BaseFdNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+
+recv_fd()[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3icmpv4l4protocol module¶

+
+
+class nepi.resources.ns3.ns3icmpv4l4protocol.NS3BaseIcmpv4L4Protocol(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3ipv4l3protocol module¶

+
+
+class nepi.resources.ns3.ns3ipv4l3protocol.NS3BaseIpv4L3Protocol(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3mobilitymodel module¶

+
+
+class nepi.resources.ns3.ns3mobilitymodel.NS3BaseMobilityModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+ +
+
+

nepi.resources.ns3.ns3netdevice module¶

+
+
+class nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+ascii_helper_uuid[source]¶
+
+ +
+
+channel[source]¶
+
+ +
+
+device_helper_uuid[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+queue[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3node module¶

+
+
+class nepi.resources.ns3.ns3node.NS3BaseNode(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+arp[source]¶
+
+ +
+
+dceapplications[source]¶
+
+ +
+
+devices[source]¶
+
+ +
+
+ipv4[source]¶
+
+ +
+
+mobility[source]¶
+
+ +
+
+node_id[source]¶
+
+ +
+
+simulation[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3pipechanel module¶

+
+
+class nepi.resources.ns3.ns3pipechanel.NS3BasePipeChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+

Interconnects two FdNetDevices with a PIPE

+
+
+devices[source]¶
+
+ +
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3propagationdelaymodel module¶

+
+
+class nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+channel[source]¶
+
+ +
+
+simulation[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3propagationlossmodel module¶

+
+
+class nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+channel[source]¶
+
+ +
+
+simulation[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3queue module¶

+
+
+class nepi.resources.ns3.ns3queue.NS3BaseQueue(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+device[source]¶
+
+ +
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3route module¶

+
+
+class nepi.resources.ns3.ns3route.NS3Route(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3server module¶

+
+
+class nepi.resources.ns3.ns3server.NS3WrapperMessage[source]¶
+
+
+CREATE = 'CREATE'¶
+
+ +
+
+FACTORY = 'FACTORY'¶
+
+ +
+
+FLUSH = 'FLUSH'¶
+
+ +
+
+GET = 'GET'¶
+
+ +
+
+INVOKE = 'INVOKE'¶
+
+ +
+
+SET = 'SET'¶
+
+ +
+
+SHUTDOWN = 'SHUTDOWN'¶
+
+ +
+
+START = 'START'¶
+
+ +
+
+STOP = 'STOP'¶
+
+ +
+ +
+
+nepi.resources.ns3.ns3server.close_socket(sock)[source]¶
+
+ +
+
+nepi.resources.ns3.ns3server.get_options()[source]¶
+
+ +
+
+nepi.resources.ns3.ns3server.handle_message(ns3_wrapper, msg_type, args, kwargs)[source]¶
+
+ +
+
+nepi.resources.ns3.ns3server.open_socket(socket_name)[source]¶
+
+ +
+
+nepi.resources.ns3.ns3server.recv_msg(conn)[source]¶
+
+ +
+
+nepi.resources.ns3.ns3server.run_server(socket_name, level=20, ns_log=None, enable_dump=False)[source]¶
+
+ +
+
+nepi.resources.ns3.ns3server.send_reply(conn, reply)[source]¶
+
+ +
+
+

nepi.resources.ns3.ns3simulation module¶

+
+
+class nepi.resources.ns3.ns3simulation.NS3Simulation[source]¶
+

Bases: object

+
+
+client[source]¶
+
+ +
+
+create(*args, **kwargs)[source]¶
+
+ +
+
+factory(*args, **kwargs)[source]¶
+
+ +
+
+flush(*args, **kwargs)[source]¶
+
+ +
+
+invoke(*args, **kwargs)[source]¶
+
+ +
+
+ns3_get(*args, **kwargs)[source]¶
+
+ +
+
+ns3_set(*args, **kwargs)[source]¶
+
+ +
+
+shutdown(*args, **kwargs)[source]¶
+
+ +
+
+start(*args, **kwargs)[source]¶
+
+ +
+
+stop(*args, **kwargs)[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3wifichannel module¶

+
+
+class nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+phys[source]¶
+
+ +
+
+simulation[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3wifimac module¶

+
+
+class nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+device[source]¶
+
+ +
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3wifinetdevice module¶

+
+
+class nepi.resources.ns3.ns3wifinetdevice.NS3BaseWifiNetDevice(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice

+
+ +
+
+

nepi.resources.ns3.ns3wifiphy module¶

+
+
+class nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+channel[source]¶
+
+ +
+
+device[source]¶
+
+ +
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3wifiremotestationmanager module¶

+
+
+class nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager(ec, guid)[source]¶
+

Bases: nepi.resources.ns3.ns3base.NS3Base

+
+
+device[source]¶
+
+ +
+
+node[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.ns3wrapper module¶

+
+
+class nepi.resources.ns3.ns3wrapper.NS3Wrapper(loglevel=20, enable_dump=False)[source]¶
+

Bases: object

+
+
+allowed_types[source]¶
+
+ +
+
+create(clazzname, *args)[source]¶
+

This method should be used to construct ns-3 objects that +do not have a TypeId (e.g. Values)

+
+ +
+
+debuger[source]¶
+
+ +
+
+factory(type_name, **kwargs)[source]¶
+

This method should be used to construct ns-3 objects +that have a TypeId and related introspection information

+
+ +
+
+get(uuid, name)[source]¶
+
+ +
+
+get_object(uuid)[source]¶
+
+ +
+
+invoke(uuid, operation, *args, **kwargs)[source]¶
+
+ +
+
+is_finished[source]¶
+
+ +
+
+is_running[source]¶
+
+ +
+
+is_started[source]¶
+
+ +
+
+logger[source]¶
+
+ +
+
+make_uuid()[source]¶
+
+ +
+
+ns3[source]¶
+
+ +
+
+replace_args(args)[source]¶
+
+ +
+
+replace_kwargs(kwargs)[source]¶
+
+ +
+
+set(uuid, name, value)[source]¶
+
+ +
+
+shutdown()[source]¶
+
+ +
+
+start()[source]¶
+
+ +
+
+stop(time=None)[source]¶
+
+ +
+ +
+
+nepi.resources.ns3.ns3wrapper.load_ns3_libraries()[source]¶
+
+ +
+
+nepi.resources.ns3.ns3wrapper.load_ns3_module()[source]¶
+
+ +
+
+

nepi.resources.ns3.ns3wrapper_debug module¶

+
+
+class nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger(enabled)[source]¶
+

Bases: object

+
+
+dump_create(uuid, clazzname, args)[source]¶
+
+ +
+
+dump_factory(uuid, type_name, kwargs)[source]¶
+
+ +
+
+dump_get(uuid, name)[source]¶
+
+ +
+
+dump_header()[source]¶
+
+ +
+
+dump_invoke(newuuid, uuid, operation, args, kwargs)[source]¶
+
+ +
+
+dump_set(uuid, name, value)[source]¶
+
+ +
+
+dump_shutdown()[source]¶
+
+ +
+
+dump_start()[source]¶
+
+ +
+
+dump_stop(time=None)[source]¶
+
+ +
+
+dump_to_script(command)[source]¶
+
+ +
+
+enabled[source]¶
+
+ +
+
+format_args(args)[source]¶
+
+ +
+
+format_kwargs(kwargs)[source]¶
+
+ +
+
+format_value(value)[source]¶
+
+ +
+
+script_path[source]¶
+
+ +
+ +
+
+

nepi.resources.ns3.resource_manager_generator module¶

+
+
+nepi.resources.ns3.resource_manager_generator.create_ns3_rms()[source]¶
+
+ +
+
+nepi.resources.ns3.resource_manager_generator.select_base_class(ns3, tid)[source]¶
+
+ +
+
+nepi.resources.ns3.resource_manager_generator.template_attributes(ns3, tid)[source]¶
+
+ +
+
+nepi.resources.ns3.resource_manager_generator.template_traces(ns3, tid)[source]¶
+
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.omf.html b/doc/sphinx/_build/html/_layout/nepi.resources.omf.html new file mode 100644 index 00000000..c4353be0 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.omf.html @@ -0,0 +1,1597 @@ + + + + + + + + nepi.resources.omf package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

nepi.resources.omf package¶

+
+

Submodules¶

+
+
+

nepi.resources.omf.application module¶

+
+
+class nepi.resources.omf.application.OMFApplication(ec, guid)[source]¶
+

Bases: nepi.resources.omf.omf_resource.OMFResource

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • ec (ExperimentController) – The Experiment controller
  • +
  • guid (int) – guid of the RM
  • +
+
+
+ +
+
+add_set_hook()[source]¶
+

Initialize the hooks for OMF 5.4 only

+
+ +
+
+check_deploy(cid)[source]¶
+

Check, through the mail box in the parser, +if the confirmation of the creation has been received

+ +++ + + + +
Parameters:cid – the id of the original message
+
+ +
+
+check_release(cid)[source]¶
+

Check, through the mail box in the parser, +if the confirmation of the release has been received

+ +++ + + + +
Parameters:cid – the id of the original message
+
+ +
+
+check_start(uid)[source]¶
+

Check, through the mail box in the parser, +if the confirmation of the start has been received

+ +++ + + + +
Parameters:uid – the id of the original message
+
+ +
+
+do_deploy()[source]¶
+

Deploy the RM. It means nothing special for an application +for now (later it will be upload sources, ...) +It becomes DEPLOYED after the topic for the application has been created

+
+ +
+
+do_release()[source]¶
+

Clean the RM at the end of the experiment and release the API.

+
+ +
+
+do_start()[source]¶
+

Start the RM. It means : Send Xmpp Message Using OMF protocol +to execute the application.

+
+ +
+
+do_stop()[source]¶
+

Stop the RM. It means : Send Xmpp Message Using OMF protocol to +kill the application. +State is set to STOPPED after the message is sent.

+
+ +
+
+exp_id[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+stdin_hook(old_value, new_value)[source]¶
+

Set a hook to the stdin attribute in order to send a message at each time +the value of this parameter is changed. Used ofr OMF 5.4 only

+
+ +
+
+trace(name, attr='all', block=512, offset=0)[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+

Check if the connection with the guid in parameter is possible. +Only meaningful connections are allowed.

+ +++ + + + + + +
Parameters:guid (int) – Guid of RM it will be connected
Return type:Boolean
+
+ +
+ +
+
+

nepi.resources.omf.channel module¶

+
+
+class nepi.resources.omf.channel.OMFChannel(ec, guid)[source]¶
+

Bases: nepi.resources.omf.omf_resource.OMFResource

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • ec (ExperimentController) – The Experiment controller
  • +
  • guid (int) – guid of the RM
  • +
  • creds (dict) – Credentials to communicate with the rm (XmppClient for OMF)
  • +
+
+
+ +
+
+ChannelToFreq = {'11': '2462', '10': '2457', '13': '2472', '12': '2467', '1': '2412', '3': '2422', '2': '2417', '5': '2432', '4': '2427', '7': '2442', '6': '2437', '9': '2452', '8': '2447'}¶
+
+ +
+
+do_deploy()[source]¶
+

Deploy the RM. It means : Get the xmpp client and send messages +using OMF 5.4 or 6 protocol to configure the channel.

+
+ +
+
+do_release()[source]¶
+

Clean the RM at the end of the experiment and release the API

+
+ +
+
+exp_id[source]¶
+
+ +
+
+get_frequency(channel)[source]¶
+

Returns the frequency of a specific channel number

+
+ +
+
+valid_connection(guid)[source]¶
+

Check if the connection with the guid in parameter is possible. +Only meaningful connections are allowed.

+ +++ + + + + + +
Parameters:guid (int) – Guid of the current RM
Return type:Boolean
+
+ +
+ +
+
+

nepi.resources.omf.interface module¶

+
+
+class nepi.resources.omf.interface.OMFWifiInterface(ec, guid)[source]¶
+

Bases: nepi.resources.omf.omf_resource.OMFResource

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • ec (ExperimentController) – The Experiment controller
  • +
  • guid (int) – guid of the RM
  • +
+
+
+ +
+
+channel[source]¶
+
+ +
+
+check_deploy(cid)[source]¶
+

Check, through the mail box in the parser, +if the confirmation of the creation has been received

+ +++ + + + +
Parameters:cid – the id of the original message
+
+ +
+
+check_release(cid)[source]¶
+

Check, through the mail box in the parser, +if the confirmation of the release has been received

+ +++ + + + +
Parameters:cid – the id of the original message
+
+ +
+
+configure_iface()[source]¶
+

Configure the interface without the ip

+
+ +
+
+configure_ip()[source]¶
+

Configure the ip of the interface

+

CELL ID shraing problem. By putting th ip at the end of the configuration, +each node use the same channel and can then share the same CELL ID. +In the second case, the channel is defined at the end and the node don’t +share a common CELL ID and can not communicate.

+
+ +
+
+configure_on_omf5()[source]¶
+

Method to configure the wifi interface when OMF 5.4 is used.

+
+ +
+
+configure_on_omf6()[source]¶
+

Method to configure the wifi interface when OMF 6 is used.

+
+ +
+
+do_deploy()[source]¶
+

Deploy the RM. It means : Get the xmpp client and send messages +using OMF 5.4 or 6 protocol to configure the interface.

+
+ +
+
+do_release()[source]¶
+

Clean the RM at the end of the experiment and release the API

+
+ +
+
+exp_id[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+

Check if the connection with the guid in parameter is possible. +Only meaningful connections are allowed.

+ +++ + + + + + +
Parameters:guid (int) – Guid of the current RM
Return type:Boolean
+
+ +
+ +
+
+

nepi.resources.omf.messages_5_4 module¶

+
+
+class nepi.resources.omf.messages_5_4.MessageHandler(sliceid, expid)[source]¶
+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • sliceid – Slice Name (= Xmpp Slice)
  • +
  • expid (str) – Experiment ID (= Xmpp User)
  • +
+
+
+ +
+

Note

+

This class is used only for OMF 5.4 Protocol and is going to become unused

+
+
+
+alias_function(name, target)[source]¶
+

Build an Alias Message

+ +++ + + + +
Parameters:
    +
  • name (str) – Name of the new alias
  • +
  • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
  • +
+
+
+ +
+
+configure_function(target, value, path)[source]¶
+

Build a Configure Message

+ +++ + + + +
Parameters:
    +
  • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
  • +
  • value (int) – guid of the RM
  • +
  • path (dict) – Path of the element to configure (ex : net/w0/channel)
  • +
+
+
+ +
+
+enroll_function(enrollkey, image, index, target)[source]¶
+

Build an Enroll Message

+ +++ + + + +
Parameters:
    +
  • enrollkey (str) – Type of enrollment (= 1)
  • +
  • image (str) – Image (= * when all the nodes are concerned)
  • +
  • index (str) – Index (= 1 in general)
  • +
  • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
  • +
+
+
+ +
+
+execute_function(target, appid, cmdlineargs, path, env)[source]¶
+

Build an Execute Message

+ +++ + + + +
Parameters:
    +
  • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
  • +
  • appid (str) – Application id
  • +
  • cmdlineargs (str) – Arguments of the application
  • +
  • path (str) – Path of the application
  • +
  • env (str) – Environment variables
  • +
+
+
+ +
+
+exit_function(target, appid)[source]¶
+

Build an Exit Message

+ +++ + + + +
Parameters:
    +
  • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
  • +
  • appid (str) – Application id (ex : vlc#1)
  • +
+
+
+ +
+
+log_function(level, logger, level_name, data)[source]¶
+

Build a Log Message

+ +++ + + + +
Parameters:
    +
  • level (str) – Level of logging
  • +
  • logger (str) – Element publishing the log
  • +
  • level_name (str) – Name of the level (ex : INFO)
  • +
  • data (str) – Content to publish
  • +
+
+
+ +
+
+newexp_function(experimentid, address)[source]¶
+

Build a NewExp Message

+ +++ + + + +
Parameters:
    +
  • experimentid (str) – Id of the new experiment
  • +
  • address (str) – Adress of the destination set of nodes
  • +
+
+
+ +
+
+noop_function(target)[source]¶
+

Build a Noop Message

+ +++ + + + +
Parameters:target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
+
+ +
+
+stdin_function(target, value, appid)[source]¶
+

Build an Execute Message

+ +++ + + + +
Parameters:
    +
  • value (str) – parameter that go in the stdin
  • +
  • target (str) – Hrn of the target node (ex : omf.plexus.wlab17)
  • +
  • appid (str) – Application id
  • +
+
+
+ +
+ +
+
+

nepi.resources.omf.messages_6 module¶

+
+
+class nepi.resources.omf.messages_6.MessageHandler[source]¶
+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • sliceid – Slice Name (= Xmpp Slice)
  • +
  • expid (str) – Experiment ID (= Xmpp User)
  • +
+
+
+ +
+

Note

+

This class is used only for OMF 5.4 Protocol and is going to become unused

+
+
+
+configure_function(msg_id, src, timestamp, props=None, guards=None)[source]¶
+

Build a configure message

+ +++ + + + +
Parameters:
    +
  • msg_id (str) – Id of the message
  • +
  • src (str) – Src node that send the message (jabber source)
  • +
  • timestamp (str) – Unix Timestamp
  • +
  • props (list) – List of properties
  • +
  • guards (list) – list of guards (assertions for properties)
  • +
+
+
+ +
+
+create_function(msg_id, src, rtype, timestamp, props=None, guards=None)[source]¶
+

Build a create message

+ +++ + + + +
Parameters:
    +
  • msg_id (str) – Id of the message
  • +
  • src (str) – Src node that send the message (jabber source)
  • +
  • rtype (str) – Type of the object
  • +
  • timestamp (str) – Unix Timestamp
  • +
  • props (list) – List of properties
  • +
  • guards (list) – list of guards (assertions for properties)
  • +
+
+
+ +
+
+release_function(msg_id, src, timestamp, res_id=None, props=None, guards=None)[source]¶
+

Build a release message

+ +++ + + + +
Parameters:
    +
  • msg_id (str) – Id of the message
  • +
  • src (str) – Src node that send the message (jabber source)
  • +
  • timestamp (str) – Unix Timestamp
  • +
  • res_id (str) – Id of the release resource
  • +
  • props (list) – List of properties
  • +
  • guards (list) – list of guards (assertions for properties)
  • +
+
+
+ +
+
+request_function(msg_id, src, timestamp, props=None, guards=None)[source]¶
+

Build a request message

+ +++ + + + +
Parameters:
    +
  • msg_id (str) – Id of the message
  • +
  • src (str) – Src node that send the message (jabber source)
  • +
  • timestamp (str) – Unix Timestamp
  • +
  • props (list) – List of properties
  • +
  • guards (list) – list of guards (assertions for properties)
  • +
+
+
+ +
+ +
+
+

nepi.resources.omf.node module¶

+
+
+class nepi.resources.omf.node.OMFNode(ec, guid)[source]¶
+

Bases: nepi.resources.omf.omf_resource.OMFResource

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • ec (ExperimentController) – The Experiment controller
  • +
  • guid (int) – guid of the RM
  • +
  • creds (dict) – Credentials to communicate with the rm (XmppClient for OMF)
  • +
+
+
+ +
+
+do_deploy()[source]¶
+

Deploy the RM. It means : Send Xmpp Message Using OMF protocol +to enroll the node into the experiment.

+
+ +
+
+do_release()[source]¶
+

Clean the RM at the end of the experiment by unenrolling +the node from the topic

+
+ +
+
+exp_id[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+

Check if the connection with the guid in parameter is possible. +Only meaningful connections are allowed.

+ +++ + + + + + +
Parameters:guid (int) – Guid of the current RM
Return type:Boolean
+
+ +
+ +
+
+

nepi.resources.omf.omf5_api module¶

+
+
+class nepi.resources.omf.omf5_api.OMF5API(host, slice, port, password, xmpp_root=None, exp_id=None)[source]¶
+

Bases: nepi.util.logger.Logger

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • host (str) – Xmpp Server
  • +
  • slice (str) – Xmpp Slice
  • +
  • port (str) – Xmpp Port
  • +
  • password (str) – Xmpp password
  • +
  • xmpp_root (str) – Root of the Xmpp Topic Architecture
  • +
+
+
+ +
+

Note

+

This class is the implementation of an OMF 5.4 API. +Since the version 5.4.1, the Topic Architecture start with OMF_5.4 +instead of OMF used for OMF5.3

+
+
+
+configure(hostname, attribute, value)[source]¶
+

Configure attribute on the node

+ +++ + + + +
Parameters:
    +
  • hostname (str) – Full hrn of the node
  • +
  • attribute (str) – Attribute that need to be configured ( +often written as /net/wX/attribute, with X the interface number)
  • +
  • value (str) – Value of the attribute
  • +
+
+
+ +
+
+delete(hostname)[source]¶
+

Delete the topic corresponding to the hostname for this session

+ +++ + + + +
Parameters:hostname (str) – Full hrn of the node
+
+ +
+
+disconnect()[source]¶
+

Delete the session and logger topics. Then disconnect

+
+ +
+
+enroll_host(hostname)[source]¶
+
+
Create and Subscribe to the session topic and the resources
+
corresponding to the hostname
+
+ +++ + + + +
Parameters:hostname (str) – Full hrn of the node
+
+ +
+
+execute(hostname, app_id, arguments, path, env)[source]¶
+

Execute command on the node

+ +++ + + + +
Parameters:
    +
  • hostname (str) – Full hrn of the node
  • +
  • app_id (str) – Application Id (Any id that represents in a unique +way the application)
  • +
  • arguments (str) – Arguments of the application
  • +
  • path (str) – Path of the application
  • +
  • env (str) – Environnement values for the application
  • +
+
+
+ +
+
+exit(hostname, app_id)[source]¶
+

Kill an application started with OMF

+ +++ + + + +
Parameters:
    +
  • hostname (str) – Full hrn of the node
  • +
  • app_id (str) – Application Id of the application you want to stop
  • +
+
+
+ +
+
+release(hostname)[source]¶
+

Delete the session and logger topics. Then disconnect

+
+ +
+
+send_stdin(hostname, value, app_id)[source]¶
+

Send to the stdin of the application the value

+ +++ + + + +
Parameters:
    +
  • hostname (str) – Full hrn of the node
  • +
  • appid (str) – Application Id (Any id that represents in a unique +way the application)
  • +
  • value (str) – parameter to execute in the stdin of the application
  • +
+
+
+ +
+ +
+
+

nepi.resources.omf.omf6_api module¶

+
+
+class nepi.resources.omf.omf6_api.OMF6API(server, user='nepi', port='5222', password='1234', exp_id=None)[source]¶
+

Bases: nepi.util.logger.Logger

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • server (str) – Xmpp Server
  • +
  • user (str) – Xmpp User
  • +
  • port (str) – Xmpp Port
  • +
  • password (str) – Xmpp password
  • +
  • xmpp_root (str) – Root of the Xmpp Topic Architecture
  • +
+
+
+ +
+

Note

+

This class is the implementation of an OMF 5.4 API. +Since the version 5.4.1, the Topic Architecture start with OMF_5.4 +instead of OMF used for OMF5.3

+
+
+
+check_mailbox(itype, attr)[source]¶
+

Check the mail box

+ +++ + + + +
Parameters:
    +
  • itype (str) – type of mail
  • +
  • attr (str) – value wanted
  • +
+
+
+ +
+
+check_ready(xmpp)[source]¶
+
+ +
+
+create_and_enroll_topic(topic)[source]¶
+
+
Create and Subscribe to the session topic and the resources
+
corresponding to the hostname
+
+ +++ + + + +
Parameters:hostname (str) – Full hrn of the node
+
+ +
+
+disconnect()[source]¶
+

Delete the session and logger topics. Then disconnect

+
+ +
+
+enroll_topic(topic)[source]¶
+

Create and Subscribe to the session topic and the resources +corresponding to the hostname

+
+ +
+
+frcp_configure(topic, props=None, guards=None)[source]¶
+

Publish a configure message

+
+ +
+
+frcp_create(msg_id, topic, rtype, props=None, guards=None)[source]¶
+

Publish a create message

+
+ +
+
+frcp_inform(topic, cid, itype)[source]¶
+

Publish an inform message

+
+ +
+
+frcp_release(msg_id, parent, child, res_id=None, props=None, guards=None)[source]¶
+

Publish a release message

+
+ +
+
+frcp_request(topic, props=None, guards=None)[source]¶
+

Execute command on the node

+
+ +
+
+unenroll_topic(topic)[source]¶
+

Create and Subscribe to the session topic and the resources +corresponding to the hostname

+
+ +
+ +
+
+

nepi.resources.omf.omf6_parser module¶

+
+
+class nepi.resources.omf.omf6_parser.OMF6Parser[source]¶
+

Bases: nepi.util.logger.Logger

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • jid (str) – Jabber Id (= Xmpp Slice + Date)
  • +
  • password (str) – Jabber Password (= Xmpp Password)
  • +
+
+
+ +
+

Note

+

This class is an XMPP Client with customized method

+
+
+
+check_mailbox(itype, attr)[source]¶
+

Check the mail box

+ +++ + + + +
Parameters:
    +
  • itype (str) – type of mail
  • +
  • attr (str) – value wanted
  • +
+
+
+ +
+
+handle(iq)[source]¶
+

Check the mail box

+ +++ + + + +
Parameters:iq – message received
+
+ +
+
+init_mailbox()[source]¶
+
+ +
+ +
+
+

nepi.resources.omf.omf_api_factory module¶

+
+
+class nepi.resources.omf.omf_api_factory.OMFAPIFactory[source]¶
+

Bases: object

+
+

Note

+

It allows the different RM to use the same xmpp client if they use +the same credentials. For the moment, it is focused on XMPP.

+
+
+
+classmethod create_api(version, server, user, port, password, exp_id)[source]¶
+

Create an OMF API if this one doesn’t exist yet with this credentials

+ +++ + + + +
Parameters:
    +
  • version (str) – OMF Version. Either 5 or 6
  • +
  • server (str) – Xmpp Server Adress
  • +
  • user (str) – Xmpp User
  • +
  • port (str) – Xmpp Port (Default : 5222)
  • +
  • password (str) – Xmpp Password
  • +
  • exp_id (str) – Id of the experiment
  • +
+
+
+ +
+
+classmethod get_api(version, server, user, port, password, exp_id=None)[source]¶
+

Get an OMF Api

+ +++ + + + +
Parameters:
    +
  • version (str) – OMF Version. Either 5 or 6
  • +
  • server (str) – Xmpp Server Adress
  • +
  • user (str) – Xmpp User
  • +
  • port (str) – Xmpp Port (Default : 5222)
  • +
  • password (str) – Xmpp Password
  • +
  • exp_id (str) – Id of the experiment
  • +
+
+
+ +
+
+lock = <thread.lock object at 0x7f028fc193b0>¶
+
+ +
+
+classmethod release_api(version, server, user, port, password, exp_id=None)[source]¶
+

Release an OMF API with this credentials

+ +++ + + + +
Parameters:
    +
  • version (str) – OMF Version. Either 5 or 6
  • +
  • server (str) – Xmpp Server Adress
  • +
  • user (str) – Xmpp User
  • +
  • port (str) – Xmpp Port (Default : 5222)
  • +
  • password (str) – Xmpp Password
  • +
  • exp_id (str) – Id of the experiment
  • +
+
+
+ +
+ +
+
+

nepi.resources.omf.omf_client module¶

+
+
+class nepi.resources.omf.omf_client.BaseOMFClient(jid, password, ssl=False, plugin_config={}, plugin_whitelist=[], escape_quotes=True, sasl_mech=None)[source]¶
+

Bases: sleekxmpp.clientxmpp.ClientXMPP

+
+ +
+
+class nepi.resources.omf.omf_client.OMFClient(jid, password)[source]¶
+

Bases: nepi.resources.omf.omf_client.BaseOMFClient, nepi.util.logger.Logger

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • jid (str) – Jabber Id (= Xmpp Slice + Date)
  • +
  • password (str) – Jabber Password (= Xmpp Password)
  • +
+
+
+ +
+

Note

+

This class is an XMPP Client with customized method

+
+
+
+check_mailbox(itype, attr)[source]¶
+

Check the mail box

+ +++ + + + +
Parameters:
    +
  • itype (str) – type of mail
  • +
  • attr (str) – value wanted
  • +
+
+
+ +
+
+create(node)[source]¶
+

Create the topic corresponding to the node

+ +++ + + + +
Parameters:node (str) – Name of the topic, corresponding to the node (ex : omf.plexus.wlab17)
+
+ +
+
+delete(node)[source]¶
+

Delete the topic corresponding to the node

+ +++ + + + +
Parameters:node (str) – Name of the topic, corresponding to the node (ex : omf.plexus.wlab17)
+
+ +
+
+get(data)[source]¶
+

Get the item

+ +++ + + + +
Parameters:data (str) – data from which the items will be get back
+
+ +
+
+handle_omf_message(iq)[source]¶
+

Handle published/received message

+ +++ + + + +
Parameters:iq (Iq Stanza) – Stanzas that is currently published/received
+
+ +
+
+nodes()[source]¶
+

Get all the nodes of the Xmppp Server.

+
+ +
+
+publish(data, node)[source]¶
+

Publish the data to the corresponding topic

+ +++ + + + +
Parameters:
    +
  • data (str) – Data that will be published
  • +
  • node (str) – Name of the topic
  • +
+
+
+ +
+
+purge()[source]¶
+

Purge the information in the server

+
+ +
+
+ready[source]¶
+

Check if the client is ready

+
+ +
+
+register(iq)[source]¶
+

Register to the Xmppp Server. This function is called directly by the sleekXmpp library

+
+ +
+
+retract(data)[source]¶
+

Retract the item

+ +++ + + + +
Parameters:data (str) – data from which the item will be retracted
+
+ +
+
+start(event)[source]¶
+

Send presence to the Xmppp Server. This function is called directly by the sleekXmpp library

+
+ +
+
+subscribe(node)[source]¶
+

Subscribe to a topic

+ +++ + + + +
Parameters:node (str) – Name of the topic
+
+ +
+
+subscriptions()[source]¶
+

Get all the subscriptions of the Xmppp Server.

+
+ +
+
+unregister()[source]¶
+

Unregister from the Xmppp Server.

+
+ +
+
+unsubscribe(node)[source]¶
+

Unsubscribe to a topic

+ +++ + + + +
Parameters:node (str) – Name of the topic
+
+ +
+ +
+
+

nepi.resources.omf.omf_resource module¶

+
+
+class nepi.resources.omf.omf_resource.OMFResource(ec, guid)[source]¶
+

Bases: nepi.execution.resource.ResourceManager

+

Generic resource gathering XMPP credential information and common methods +for OMF nodes, channels, applications, etc.

+
+ +
+
+class nepi.resources.omf.omf_resource.ResourceGateway[source]¶
+

Dictionary used to set OMF gateway depending on Testbed information.

+
+
+AMtoGateway = {'nitlab.inf.uth.gr': 'nitlab.inf.uth.gr', 'nicta': '??.??.??', 'am.wilab2.ilabt.iminds.be': 'ops.wilab2.ilabt.iminds.be'}¶
+
+ +
+
+TestbedtoGateway = {'wilabt': 'ops.wilab2.ilabt.iminds.be', 'nicta': '??.??.??', 'nitos': 'nitlab.inf.uth.gr'}¶
+
+ +
+ +
+
+

nepi.resources.omf.wilabt_node module¶

+
+
+class nepi.resources.omf.wilabt_node.WilabtSfaNode(ec, guid)[source]¶
+

Bases: nepi.resources.omf.node.OMFNode

+
+
+do_deploy()[source]¶
+
+ +
+
+do_discover()[source]¶
+

Based on the attributes defined by the user, discover the suitable +node for provision.

+
+ +
+
+do_provision()[source]¶
+

Add node to user’s slice and verifing that the node is functioning +correctly. Check ssh, omf rc running, hostname, file system.

+
+ +
+
+do_release()[source]¶
+
+ +
+
+execute(command, sudo=False, env=None, tty=False, forward_x11=False, retry=3, connect_timeout=30, strict_host_checking=False, persistent=True, blocking=True)[source]¶
+

Notice that this invocation will block until the +execution finishes. If this is not the desired behavior, +use ‘run’ instead.

+
+ +
+
+fail_discovery()[source]¶
+
+ +
+
+fail_node_not_alive(host=None)[source]¶
+
+ +
+
+fail_node_not_available(host)[source]¶
+
+ +
+
+fail_not_enough_nodes()[source]¶
+
+ +
+
+fail_sfaapi()[source]¶
+
+ +
+
+sfaapi[source]¶
+

Property to instanciate the SFA API based in sfi client. +For each SFA method called this instance is used.

+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.html b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.html new file mode 100644 index 00000000..8477bca4 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.html @@ -0,0 +1,629 @@ + + + + + + + + nepi.resources.planetlab package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

nepi.resources.planetlab package¶

+ +
+

Submodules¶

+
+
+

nepi.resources.planetlab.node module¶

+
+
+class nepi.resources.planetlab.node.PlanetlabNode(ec, guid)[source]¶
+

Bases: nepi.resources.linux.node.LinuxNode

+
+
+do_discover()[source]¶
+

Based on the attributes defined by the user, discover the suitable +nodes for provision.

+
+ +
+
+do_provision()[source]¶
+

Add node to user’s slice after verifing that the node is functioning +correctly

+
+ +
+
+do_release()[source]¶
+
+ +
+
+fail_discovery()[source]¶
+
+ +
+
+fail_node_not_alive(hostname=None)[source]¶
+
+ +
+
+fail_node_not_available(hostname)[source]¶
+
+ +
+
+fail_not_enough_nodes()[source]¶
+
+ +
+
+fail_plapi()[source]¶
+
+ +
+
+lock = <thread.lock object at 0x7f028fc19a70>¶
+
+ +
+
+plapi[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.planetlab.plcapi module¶

+
+
+class nepi.resources.planetlab.plcapi.PLCAPI(username, password, hostname, urlpattern, ec, proxy, session_key=None, local_peer='PLE')[source]¶
+

Bases: object

+
+
+add_slice_nodes(slicename, nodes)[source]¶
+
+ +
+
+api[source]¶
+
+ +
+
+blacklist_host(node_id)[source]¶
+
+ +
+
+blacklisted()[source]¶
+
+ +
+
+delete_slice_node(slice_id_or_name, node_id_or_hostname)[source]¶
+
+ +
+
+finish_multicall()[source]¶
+
+ +
+
+get_interfaces(interface_id_or_ip=None, fields=None, **kw)[source]¶
+
+ +
+
+get_node_flavour(node)[source]¶
+

Returns detailed information on a given node’s flavour, +i.e. its base installation.

+

This depends on the global PLC settings in the PLC_FLAVOUR area, +optionnally overridden by any of the following tags if set on that node: +‘arch’, ‘pldistro’, ‘fcdistro’, ‘deployment’, ‘extensions’

+

Params:

+
+
    +
  • +
    node : int or string
    +
      +
    • int, Node identifier
    • +
    • string, Fully qualified hostname
    • +
    +
    +
    +
  • +
+
+

Returns:

+
+
+
struct
+
    +
  • extensions : array of string, extensions to add to the base install
  • +
  • fcdistro : string, the fcdistro this node should be based upon
  • +
  • nodefamily : string, the nodefamily this node should be based upon
  • +
  • plain : boolean, use plain bootstrapfs image if set (for tests)
  • +
+
+
+
+
+ +
+
+get_node_info(node_id)[source]¶
+
+ +
+
+get_node_tags(node_tag_id=None, fields=None, **kw)[source]¶
+
+ +
+
+get_nodes(node_id_or_name=None, fields=None, **kw)[source]¶
+

Returns an array of structs containing details about nodes. +If node_id_or_name is specified and is an array of node identifiers +or hostnames, or the filters keyword argument with struct of node +attributes, or node attributes by keyword argument, +only nodes matching the filter will be returned.

+

If fields is specified, only the specified details will be returned. +NOTE that if fields is unspecified, the complete set of native fields are +returned, which DOES NOT include tags at this time.

+

Some fields may only be viewed by admins.

+

Special params:

+
+

fields: an optional list of fields to retrieve. The default is all.

+
+
filters: an optional mapping with custom filters, which is the only
+
way to support complex filters like negation and numeric comparisons.
+
peer: a string (or sequence of strings) with the name(s) of peers
+
to filter - or None for local nodes.
+
+
+
+ +
+
+get_slice_id(slicename)[source]¶
+
+ +
+
+get_slice_nodes(slicename)[source]¶
+
+ +
+
+get_slice_tags(slice_tag_id=None, fields=None, **kw)[source]¶
+
+ +
+
+get_slice_vnet_sys_tag(slicename)[source]¶
+
+ +
+
+get_slices(slice_id_or_name=None, fields=None, **kw)[source]¶
+
+ +
+
+mcapi[source]¶
+
+ +
+
+network_types[source]¶
+
+ +
+
+peer_map[source]¶
+
+ +
+
+release()[source]¶
+
+ +
+
+reserve_host(node_id)[source]¶
+
+ +
+
+reserved()[source]¶
+
+ +
+
+start_multicall()[source]¶
+
+ +
+
+test()[source]¶
+
+ +
+
+unblacklist_host(node_id)[source]¶
+
+ +
+
+unreserve_host(node_id)[source]¶
+
+ +
+
+update_slice(slice_id_or_name, **kw)[source]¶
+
+ +
+ +
+
+class nepi.resources.planetlab.plcapi.PLCAPIFactory[source]¶
+

Bases: object

+
+

Note

+

It allows PlanetLab RMs sharing a same slice, to use a same plcapi instance, +and to sincronize blacklisted and reserved hosts.

+
+
+
+classmethod create_api(pl_user, pl_pass, pl_host, pl_ptn, ec, proxy=None)[source]¶
+

Create an PLCAPI instance

+ +++ + + + +
Parameters:
    +
  • pl_user (str) – Planelab user name (used for web login)
  • +
  • pl_pass (str) – Planetlab password (used for web login)
  • +
  • pl_host (str) – Planetlab registry host (e.g. “www.planet-lab.eu”)
  • +
  • pl_ptn (str) – XMLRPC service pattern (e.g. https://%(hostname)s:443/PLCAPI/)
  • +
  • proxy – Proxy service url
  • +
+
+
+ +
+
+classmethod get_api(pl_user, pl_pass, pl_host, pl_ptn, ec, proxy=None)[source]¶
+

Get existing PLCAPI instance

+ +++ + + + +
Parameters:
    +
  • pl_user (str) – Planelab user name (used for web login)
  • +
  • pl_pass (str) – Planetlab password (used for web login)
  • +
  • pl_host (str) – Planetlab registry host (e.g. “www.planet-lab.eu”)
  • +
  • pl_ptn (str) – XMLRPC service pattern (e.g. https://%(hostname)s:443/PLCAPI/)
  • +
  • proxy – Proxy service url
  • +
+
+
+ +
+ +
+
+

nepi.resources.planetlab.sfa_node module¶

+
+
+class nepi.resources.planetlab.sfa_node.PlanetlabSfaNode(ec, guid)[source]¶
+

Bases: nepi.resources.linux.node.LinuxNode

+
+
+do_discover()[source]¶
+

Based on the attributes defined by the user, discover the suitable +nodes for provision.

+
+ +
+
+do_provision()[source]¶
+

Add node to user’s slice and verifing that the node is functioning +correctly. Check ssh, file system.

+
+ +
+
+do_release()[source]¶
+
+ +
+
+fail_discovery()[source]¶
+
+ +
+
+fail_node_not_alive(hostname=None)[source]¶
+
+ +
+
+fail_node_not_available(hostname)[source]¶
+
+ +
+
+fail_not_enough_nodes()[source]¶
+
+ +
+
+fail_sfaapi()[source]¶
+
+ +
+
+sfaapi[source]¶
+

Property to instanciate the SFA API based in sfi client. +For each SFA method called this instance is used.

+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

nepi.resources.planetlab.tap module¶

+
+
+class nepi.resources.planetlab.tap.PlanetlabTap(ec, guid)[source]¶
+

Bases: nepi.resources.linux.tap.LinuxTap

+
+
+gre_connect(remote_endpoint, connection_app_home, connection_run_home)[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+upload_sources()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+
+vif_name_file[source]¶
+
+ +
+
+wait_vif_name(exec_run_home=None)[source]¶
+

Waits until the vif_name file for the command is generated, +and returns the vif_name for the device

+
+ +
+ +
+
+

nepi.resources.planetlab.tun module¶

+
+
+class nepi.resources.planetlab.tun.PlanetlabTun(ec, guid)[source]¶
+

Bases: nepi.resources.planetlab.tap.PlanetlabTap

+
+ +
+
+

nepi.resources.planetlab.vroute module¶

+
+
+class nepi.resources.planetlab.vroute.PlanetlabVroute(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+do_deploy()[source]¶
+
+ +
+
+do_release()[source]¶
+
+ +
+
+do_start()[source]¶
+
+ +
+
+do_stop()[source]¶
+
+ +
+
+node[source]¶
+
+ +
+
+tap[source]¶
+
+ +
+
+upload_sources()[source]¶
+
+ +
+
+upload_start_command()[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+
+ +
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.ns3.html b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.ns3.html new file mode 100644 index 00000000..9f3b72ff --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.ns3.html @@ -0,0 +1,153 @@ + + + + + + + + nepi.resources.planetlab.ns3 package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.resources.planetlab.ns3 package¶

+
+

Submodules¶

+
+
+

nepi.resources.planetlab.ns3.fdudptunnel module¶

+
+
+class nepi.resources.planetlab.ns3.fdudptunnel.PlanetlabNs3FdUdpTunnel(ec, guid)[source]¶
+

Bases: nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel

+
+
+get_endpoints()[source]¶
+

Returns the list of RM that are endpoints to the tunnel

+
+ +
+ +
+ +
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.openvswitch.html b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.openvswitch.html new file mode 100644 index 00000000..714703b5 --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.resources.planetlab.openvswitch.html @@ -0,0 +1,321 @@ + + + + + + + + nepi.resources.planetlab.openvswitch package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.resources.planetlab.openvswitch package¶

+
+

Submodules¶

+
+
+

nepi.resources.planetlab.openvswitch.ovs module¶

+
+
+class nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • ec (ExperimentController) – The Experiment controller
  • +
  • guid (int) – guid of the RM
  • +
+
+
+ +
+
+assign_controller()[source]¶
+

Set the controller IP

+
+ +
+
+check_sliver_ovs()[source]¶
+

Check if sliver-ovs exists. If it does not exist, the execution is stopped

+
+ +
+
+create_bridge()[source]¶
+

Create the bridge/switch and check error during SSH connection

+
+ +
+
+do_deploy()[source]¶
+

Deploy the OVS Switch : Turn on the server, create the bridges +and assign the controller

+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_release()[source]¶
+

Delete the bridge and close the server.

+
+
+

to be released before releasing itself

+
+ +
+
+node[source]¶
+

Node wthat run the switch

+
+ +
+
+ovs_status()[source]¶
+

Print the status of the bridge

+
+ +
+
+servers_on()[source]¶
+

Start the openvswitch servers and check it

+
+ +
+
+valid_connection(guid)[source]¶
+

Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed.

+ +++ + + + + + +
Parameters:guid (int) – Guid of the current RM
Return type:Boolean
+
+ +
+ +
+
+

nepi.resources.planetlab.openvswitch.ovsport module¶

+
+
+class nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort(ec, guid)[source]¶
+

Bases: nepi.resources.linux.application.LinuxApplication

+
+
+Class Args :
+
+++ + + + +
Parameters:
    +
  • ec (ExperimentController) – The Experiment controller
  • +
  • guid (int) – guid of the RM
  • +
+
+
+ +
+
+check_status()[source]¶
+
+ +
+
+create_port()[source]¶
+

Create the desired port

+
+ +
+
+do_deploy()[source]¶
+

Deploy the OVS port after the OVS Switch

+
+ +
+
+do_provision()[source]¶
+
+ +
+
+do_release()[source]¶
+

Delete the port on the OVSwitch. It needs to wait for the tunnel +to be released.

+
+ +
+
+establish_udp_connection(remote_endpoint, connection_app_home, connection_run_home, port)[source]¶
+
+ +
+
+initiate_udp_connection(remote_endpoint, connection_app_home, connection_run_home, cipher, cipher_key, bwlimit, txqueuelen)[source]¶
+

Get the local_endpoint of the port

+
+ +
+
+node[source]¶
+

Node that run the switch and the ports

+
+ +
+
+ovsswitch[source]¶
+

Switch where the port is created

+
+ +
+
+port_number[source]¶
+
+ +
+
+terminate_connection(endpoint, connection_app_home, connection_run_home)[source]¶
+
+ +
+
+valid_connection(guid)[source]¶
+

Check if the connection is available.

+ +++ + + + + + +
Parameters:guid (int) – Guid of the current RM
Return type:Boolean
+
+ +
+
+verify_connection(remote_endpoint, connection_app_home, connection_run_home)[source]¶
+
+ +
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.util.html b/doc/sphinx/_build/html/_layout/nepi.util.html new file mode 100644 index 00000000..e888283b --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.util.html @@ -0,0 +1,1227 @@ + + + + + + + + nepi.util package — NEPI 3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

nepi.util package¶

+ +
+

Submodules¶

+
+
+

nepi.util.environ module¶

+
+
+nepi.util.environ.execute(cmd)[source]¶
+
+ +
+
+nepi.util.environ.backticks(cmd)[source]¶
+
+ +
+
+

nepi.util.execfuncs module¶

+
+
+nepi.util.execfuncs.lcopy(source, dest, recursive=False)[source]¶
+

Copies from/to localy.

+
+ +
+
+nepi.util.execfuncs.lexec(command, user=None, sudo=False, env=None)[source]¶
+

Executes a local command, returns ((stdout,stderr),process)

+
+ +
+
+nepi.util.execfuncs.lgetpid(pidfile)[source]¶
+

Check the pidfile of a process spawned with remote_spawn.

+
+
Parameters:
+
pidfile: the pidfile passed to remote_span
+
+

Returns:

+
+
A (pid, ppid) tuple useful for calling remote_status and remote_kill, +or None if the pidfile isn’t valid yet (maybe the process is still starting).
+
+ +
+
+nepi.util.execfuncs.lkill(pid, ppid, sudo=False)[source]¶
+

Kill a process spawned with lspawn.

+

First tries a SIGTERM, and if the process does not end in 10 seconds, +it sends a SIGKILL.

+
+
Parameters:
+

pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid

+

sudo: whether the command was run with sudo - careful killing like this.

+
+
+

Returns:

+
+
Nothing, should have killed the process
+
+ +
+
+nepi.util.execfuncs.lspawn(command, pidfile, stdout='/dev/null', stderr=<class nepi.util.sshfuncs.STDOUT at 0x7f028ff15bb0>, stdin='/dev/null', home=None, create_home=False, sudo=False, user=None)[source]¶
+

Spawn a local command such that it will continue working asynchronously.

+
+
Parameters:
+

command: the command to run - it should be a single line.

+

pidfile: path of a (ideally unique to this task) pidfile for tracking the process.

+
+
stdout: path of a file to redirect standard output to - must be a string.
+
Defaults to /dev/null
+
stderr: path of a file to redirect standard error to - string or the special STDOUT value
+
to redirect to the same file stdout was redirected to. Defaults to STDOUT.
+
+

stdin: path of a file with input to be piped into the command’s standard input

+

home: path of a folder to use as working directory - should exist, unless you specify create_home

+

create_home: if True, the home folder will be created first with mkdir -p

+

sudo: whether the command needs to be executed as root

+
+
Returns:
+

(stdout, stderr), process

+

Of the spawning process, which only captures errors at spawning time. +Usually only useful for diagnostics.

+
+
+
+ +
+
+nepi.util.execfuncs.lstatus(pid, ppid)[source]¶
+

Check the status of a process spawned with remote_spawn.

+
+
Parameters:
+
pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid
+
+

Returns:

+
+
One of NOT_STARTED, RUNNING, FINISHED
+
+ +
+
+

nepi.util.guid module¶

+
+
+class nepi.util.guid.GuidGenerator[source]¶
+

Bases: object

+
+
+next(guid=None)[source]¶
+
+ +
+ +
+
+

nepi.util.logger module¶

+
+
+class nepi.util.logger.Logger(logger_component)[source]¶
+

Bases: object

+
+
+debug(msg, out=None, err=None)[source]¶
+
+ +
+
+error(msg, out=None, err=None)[source]¶
+
+ +
+
+info(msg, out=None, err=None)[source]¶
+
+ +
+
+log(msg, level, out=None, err=None)[source]¶
+
+ +
+
+log_message(msg)[source]¶
+
+ +
+
+logger[source]¶
+
+ +
+
+warning(msg, out=None, err=None)[source]¶
+
+ +
+ +
+
+

nepi.util.manifoldapi module¶

+
+
+class nepi.util.manifoldapi.MANIFOLDAPI(username, password, hostname, urlpattern)[source]¶
+

Bases: object

+

API to query different data platforms as SFA, TopHat, OML Central Server, +using Manifold Framework, the backend of MySlice.

+
+
+add_resource_to_slice(slicename, resource_urn)[source]¶
+

Add resource to user’s slice. The query needs to specify the new +resource plus the previous resources already in the slice.

+
+ +
+
+api[source]¶
+
+ +
+
+get_resource_info(filters=None, fields=None)[source]¶
+

Create and execute the Manifold API Query to get the resources +according fields and filters. +:param filters: resource’s constraints for the experiment +:type filters: dict +:param fields: desire fields in the result of the query +:type fields: list

+
+ +
+
+get_resource_urn(filters=None)[source]¶
+

Retrieves the resources urn of the resources matching filters.

+
+ +
+
+get_session_key()[source]¶
+

Retrieves the session key, in order to use the same session for +queries.

+
+ +
+
+get_slice_resources(slicename)[source]¶
+

Retrieves resources attached to user’s slice. +return value: list of resources’ urn

+
+ +
+
+remove_resource_from_slice(slicename, resource_urn)[source]¶
+

Remove resource from user’s slice. The query needs to specify the list +of previous resources in the slice without the one to be remove.

+
+ +
+ +
+
+class nepi.util.manifoldapi.MANIFOLDAPIFactory[source]¶
+

Bases: object

+

API Factory to manage a map of MANIFOLDAPI instances as key-value pairs, it +instanciate a single instance per key. The key represents the same SFA, +MF (ManiFold) credentials.

+
+
+classmethod get_api(username, password, hostname='test.myslice.info', urlpattern='http://%(hostname)s:7080')[source]¶
+
+++ + + + +
Parameters:
    +
  • username (str) – Manifold user (also used for MySlice web login)
  • +
  • password (str) – Manifold password (also used for MySlice web login)
  • +
  • hostname (str) – Hostname of the Manifold API to query SFA, TopHat, etc
  • +
  • urlpattern (str) – Url of the Manifold API to query SFA, TopHat, etc
  • +
+
+
+ +
+
+classmethod make_key(*args)[source]¶
+
+ +
+ +
+
+

nepi.util.netgraph module¶

+
+
+class nepi.util.netgraph.NetGraph(**kwargs)[source]¶
+

Bases: object

+

NetGraph represents a network topology. +Network graphs are internally using the networkx library.

+
+
+add_edge(nid1, nid2)[source]¶
+
+ +
+
+add_node(nid)[source]¶
+
+ +
+
+annotate_edge(nid1, nid2, name, value)[source]¶
+
+ +
+
+annotate_edge_net(nid1, nid2, ip1, ip2, mask, network, prefixlen)[source]¶
+
+ +
+
+annotate_node(nid, name, value)[source]¶
+
+ +
+
+annotate_node_ip(nid, ip)[source]¶
+
+ +
+
+assign_p2p_ips(network='10.0.0.0', prefix=8, version=4)[source]¶
+

Assign IP addresses to each end of each edge of the network graph, +computing all the point to point subnets and addresses in the network +representation.

+
+
+++ + + + + + + + + + + + + + +
param network:Base network address used for subnetting.
type network:str
param prefix:Prefix for the base network address used for subnetting.
type prefixt:int
param version:IP version (either 4 or 6).
type version:int
+
+
+ +
+
+del_edge_annotation(nid1, nid2, name)[source]¶
+
+ +
+
+del_node_annotation(nid, name)[source]¶
+
+ +
+
+edge_annotation(nid1, nid2, name)[source]¶
+
+ +
+
+edge_annotations(nid1, nid2)[source]¶
+
+ +
+
+edge_net_annotation(nid1, nid2)[source]¶
+
+ +
+
+edges()[source]¶
+
+ +
+
+generate_topology(topo_type, node_count, branches=None)[source]¶
+
+ +
+
+get_p2p_info(nid1, nid2)[source]¶
+
+ +
+
+is_source(nid)[source]¶
+
+ +
+
+is_target(nid)[source]¶
+
+ +
+
+node_annotation(nid, name)[source]¶
+
+ +
+
+node_annotations(nid)[source]¶
+
+ +
+
+node_ip_annotations(nid)[source]¶
+
+ +
+
+nodes()[source]¶
+
+ +
+
+order[source]¶
+
+ +
+
+select_random_source(**kwargs)[source]¶
+

Mark a random node as source.

+
+ +
+
+select_target_zero()[source]¶
+

Mark the node 0 as target

+
+ +
+
+set_source(nid)[source]¶
+
+ +
+
+set_target(nid)[source]¶
+
+ +
+
+sources()[source]¶
+

Returns the nodes that are sources

+
+ +
+
+targets()[source]¶
+

Returns the nodes that are targets

+
+ +
+
+topo_type[source]¶
+
+ +
+
+topology[source]¶
+
+ +
+ +
+
+class nepi.util.netgraph.TopologyType[source]¶
+
+
+ADHOC = 'adhoc'¶
+
+ +
+
+LADDER = 'ladder'¶
+
+ +
+
+LINEAR = 'linear'¶
+
+ +
+
+MESH = 'mesh'¶
+
+ +
+
+STAR = 'star'¶
+
+ +
+
+TREE = 'tree'¶
+
+ +
+ +
+
+

nepi.util.parallel module¶

+
+
+class nepi.util.parallel.ParallelRun(maxthreads=None, maxqueue=None, results=True)[source]¶
+

Bases: object

+
+
+destroy()[source]¶
+
+ +
+
+empty()[source]¶
+
+ +
+
+initialize_workers()[source]¶
+
+ +
+
+join()[source]¶
+
+ +
+
+put(callable, *args, **kwargs)[source]¶
+
+ +
+
+put_nowait(callable, *args, **kwargs)[source]¶
+
+ +
+
+start()[source]¶
+
+ +
+
+sync()[source]¶
+
+ +
+ +
+
+class nepi.util.parallel.WorkerThread(group=None, target=None, name=None, args=(), kwargs=None, verbose=None)[source]¶
+

Bases: threading.Thread

+
+
+class QUIT[source]¶
+
+ +
+
+WorkerThread.attach(queue, rvqueue, delayed_exceptions)[source]¶
+
+ +
+
+WorkerThread.quit()[source]¶
+
+ +
+
+WorkerThread.run()[source]¶
+
+ +
+ +
+
+

nepi.util.plotter module¶

+
+
+class nepi.util.plotter.ECPlotter[source]¶
+

Bases: object

+
+
+plot(ec, dirpath=None, format='figure', show=False)[source]¶
+
+ +
+ +
+
+class nepi.util.plotter.PFormats[source]¶
+
+
+DOT = 'dot'¶
+
+ +
+
+FIGURE = 'figure'¶
+
+ +
+ +
+
+

nepi.util.rmatcher module¶

+
+
+nepi.util.rmatcher.find_boxes(box, all_tags=None, exact_tags=None, max_depth=1)[source]¶
+

Look for the connected boxes with the required tags, doing breath-first +search, until max_depth ( max_depth = None will traverse the entire graph ).

+
+ +
+
+nepi.util.rmatcher.match_tags(box, all_tags, exact_tags)[source]¶
+

returns True if box has required tags

+
+ +
+
+

nepi.util.serializer module¶

+
+
+class nepi.util.serializer.ECSerializer[source]¶
+

Bases: object

+
+
+load(filepath, format='xml')[source]¶
+
+ +
+
+save(ec, dirpath, format='xml')[source]¶
+
+ +
+
+serialize(ec, format='xml')[source]¶
+
+ +
+ +
+
+class nepi.util.serializer.SFormats[source]¶
+
+
+XML = 'xml'¶
+
+ +
+ +
+
+

nepi.util.sfaapi module¶

+
+
+class nepi.util.sfaapi.SFAAPI(sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, batch, rtype, timeout)[source]¶
+

Bases: object

+

API for quering the SFA service. It uses Sfi class from the tool sfi client.

+
+
+add_resource_to_slice(slicename, resource_hrn, leases=None)[source]¶
+

Get the list of resources’ urn, build the rspec string and call the allocate +and provision method.

+
+ +
+
+add_resource_to_slice_batch(slicename, resource_hrn, properties=None, leases=None)[source]¶
+

Method to add all resources together to the slice. Previous deletion of slivers. +Specially used for wilabt that doesn’t allow to add more resources to the slice +after some resources are added. Every sliver have to be deleted and the batch +has to be added at once.

+
+ +
+
+blacklist_resource(resource_hrn)[source]¶
+

Adding resource_hrn to blacklist, and taking +the resource from the reserved list.

+
+ +
+
+blacklisted(resource_hrn)[source]¶
+

Check if the resource is in the blacklist.

+
+ +
+
+get_resources_hrn(resources=None)[source]¶
+

Get list of resources hrn, without the resource info.

+
+ +
+
+get_resources_info()[source]¶
+

Get all resources and its attributes from aggregate.

+
+ +
+
+get_slice_resources(slicename)[source]¶
+

Get resources and info from slice.

+
+ +
+
+release()[source]¶
+

Remove hosts from the reserved and blacklist lists, and in case +the persist attribute is set, it saves the blacklisted hosts +in the blacklist file.

+
+ +
+
+remove_all_from_slice(slicename)[source]¶
+

De-allocate and de-provision all slivers of the named slice. +Currently sfi doesn’t support removing particular +slivers, so this method works only for removing every sliver. Setting the +resource_hrn parameter is not necessary.

+
+ +
+
+remove_resource_from_slice(slicename, resource_hrn, leases=None)[source]¶
+

Remove slivers from slice. Currently sfi doesn’t support removing particular +slivers.

+
+ +
+
+reserve_resource(resource_hrn)[source]¶
+

Add resource to the reserved list.

+
+ +
+
+reserved(resource_hrn)[source]¶
+

Check that the resource in not reserved.

+
+ +
+ +
+
+class nepi.util.sfaapi.SFAAPIFactory[source]¶
+

Bases: 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.

+
+
+classmethod get_api(sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, batch=False, rtype=None, timeout=None)[source]¶
+
+ +
+
+classmethod make_key(*args)[source]¶
+
+ +
+ +
+
+

nepi.util.sfarspec_proc module¶

+
+
+class nepi.util.sfarspec_proc.SfaRSpecProcessing(config=None)[source]¶
+

Bases: object

+

Class to process SFA RSpecs, parse the RSpec replies such as Advertisement RSpecs, +and build in the case of Request RSpecs.

+
+
+build_sfa_rspec(slice_id, resources, properties, leases)[source]¶
+

Build the XML RSpec from list of resources’ urns. +eg. resources = [“urn:publicid:IDN+ple:modenaple+node+planetlab-1.ing.unimo.it“]

+
+ +
+
+make_dict_rec(obj)[source]¶
+
+ +
+
+parse_sfa_rspec(rspec_string)[source]¶
+

Parse the RSpec XML as a string.

+
+ +
+ +
+
+

nepi.util.sshfuncs module¶

+
+
+class nepi.util.sshfuncs.ProcStatus[source]¶
+

Codes for status of remote spawned process

+
+
+FINISHED = 2¶
+
+ +
+
+NOT_STARTED = 3¶
+
+ +
+
+RUNNING = 1¶
+
+ +
+ +
+
+class nepi.util.sshfuncs.STDOUT[source]¶
+

Special value that when given to rspawn in stderr causes stderr to +redirect to whatever stdout was redirected to.

+
+ +
+
+nepi.util.sshfuncs.eintr_retry(func)[source]¶
+

Retries a function invocation when a EINTR occurs

+
+ +
+
+nepi.util.sshfuncs.gethostbyname(host)[source]¶
+
+ +
+
+nepi.util.sshfuncs.log(msg, level, out=None, err=None)[source]¶
+
+ +
+
+nepi.util.sshfuncs.make_control_path(agent, forward_x11)[source]¶
+
+ +
+
+nepi.util.sshfuncs.make_server_key_args(server_key, host, port)[source]¶
+

Returns a reference to a temporary known_hosts file, to which +the server key has been added.

+

Make sure to hold onto the temp file reference until the process is +done with it

+ +++ + + + +
Parameters:
    +
  • server_key (str) – the server public key
  • +
  • host (str) – the hostname
  • +
  • port (str) – the ssh port
  • +
+
+
+ +
+
+nepi.util.sshfuncs.openssh_has_persist()[source]¶
+

The ssh_config options ControlMaster and ControlPersist allow to +reuse a same network connection for multiple ssh sessions. In this +way limitations on number of open ssh connections can be bypassed. +However, older versions of openSSH do not support this feature. +This function is used to determine if ssh connection persist features +can be used.

+
+ +
+
+nepi.util.sshfuncs.rcopy(source, dest, port=None, gwuser=None, gw=None, recursive=False, identity=None, server_key=None, retry=3, strict_host_checking=True)[source]¶
+

Copies from/to remote sites.

+

Source and destination should have the user and host encoded +as per scp specs.

+

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.

+
+ +
+
+nepi.util.sshfuncs.resolve_hostname(host)[source]¶
+
+ +
+
+nepi.util.sshfuncs.rexec(command, host, user, port=None, gwuser=None, gw=None, agent=True, sudo=False, identity=None, server_key=None, env=None, tty=False, connect_timeout=30, retry=3, persistent=True, forward_x11=False, blocking=True, strict_host_checking=True)[source]¶
+

Executes a remote command, returns ((stdout,stderr),process)

+
+ +
+
+nepi.util.sshfuncs.rgetpid(*p, **kw)[source]¶
+

Returns the pid and ppid of a process from a remote file where the +information was stored.

+
+
+++ + + + + + + + + + + + +
param home:Path to directory where the pidfile is located
type home:str
param pidfile:Name of file containing the pid information
type pidfile:str
rtype:int
+

A (pid, ppid) tuple useful for calling rstatus and rkill, +or None if the pidfile isn’t valid yet (can happen when process is staring up)

+
+
+ +
+
+nepi.util.sshfuncs.rkill(*p, **kw)[source]¶
+

Sends a kill signal to a remote process.

+

First tries a SIGTERM, and if the process does not end in 10 seconds, +it sends a SIGKILL.

+
+
+++ + + + + + + + + + + + + + +
param pid:Process id of process to be killed
type pid:int
param ppid:Parent process id of process to be killed
type ppid:int
param sudo:Flag indicating if sudo should be used to kill the process
type sudo:bool
+
+
+ +
+
+nepi.util.sshfuncs.rspawn(command, pidfile, stdout='/dev/null', stderr=<class nepi.util.sshfuncs.STDOUT at 0x7f028ff15bb0>, stdin='/dev/null', home=None, create_home=False, sudo=False, host=None, port=None, user=None, gwuser=None, gw=None, agent=None, identity=None, server_key=None, tty=False, strict_host_checking=True)[source]¶
+

Spawn a remote command such that it will continue working asynchronously in +background.

+
+
+++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
param command:The command to run, it should be a single line.
type command:str
param pidfile:Path to a file where to store the pid and ppid of the +spawned process
type pidfile:str
param stdout:Path to file to redirect standard output. +The default value is /dev/null
type stdout:str
param stderr:Path to file to redirect standard error. +If the special STDOUT value is used, stderr will +be redirected to the same file as stdout
type stderr:str
param stdin:Path to a file with input to be piped into the command’s standard input
type stdin:str
param home:Path to working directory folder. +It is assumed to exist unless the create_home flag is set.
type home:str
param create_home:
 Flag to force creation of the home folder before +running the command
type create_home:
 bool
param sudo:Flag forcing execution with sudo user
type sudo:bool
rtype:tuple
+

(stdout, stderr), process

+

Of the spawning process, which only captures errors at spawning time. +Usually only useful for diagnostics.

+
+
+ +
+
+nepi.util.sshfuncs.rstatus(*p, **kw)[source]¶
+

Returns a code representing the the status of a remote process

+
+
+++ + + + + + + + + + + + +
param pid:Process id of the process
type pid:int
param ppid:Parent process id of process
type ppid:int
rtype:int (One of NOT_STARTED, RUNNING, FINISHED)
+
+
+ +
+
+nepi.util.sshfuncs.shell_escape(s)[source]¶
+

Escapes strings so that they are safe to use as command-line +arguments

+
+ +
+
+

nepi.util.statfuncs module¶

+
+
+nepi.util.statfuncs.compute_mean(sample)[source]¶
+
+ +
+
+

nepi.util.timefuncs module¶

+
+
+nepi.util.timefuncs.compute_delay_ms(timestamp2, timestamp1)[source]¶
+
+ +
+
+nepi.util.timefuncs.stabsformat(sdate, dbase=None)[source]¶
+

Constructs a datetime object from a string date. +The string date can be expressed as an absolute date +( i.e. format YYYYMMddHHMMSSffff ) or as a relative time +( e.g. format ‘5m’ or ‘10s’). +If the date is a relative time and the dbase parameter +is given (dbase must be datetime object), the returned +date will be dbase + sdate. If dbase is None, +current time will be used instead as base time.

+

:param date : string date +:type date : date

+
+ +
+
+nepi.util.timefuncs.stformat(sdate)[source]¶
+

Constructs a datetime object from a string date with +format YYYYMMddHHMMSSffff

+
+ +
+
+nepi.util.timefuncs.tdiff(date1, date2)[source]¶
+

Returns difference ( date1 - date2 ) as a datetime object, +where date1 and date 2 are datetime objects

+
+ +
+
+nepi.util.timefuncs.tdiffsec(date1, date2)[source]¶
+

Returns the date difference ( date1 - date2 ) in seconds, +where date1 and date 2 are datetime objects

+
+ +
+
+nepi.util.timefuncs.tnow()[source]¶
+

Returns datetime object with the current time

+
+ +
+
+nepi.util.timefuncs.tsformat(date=None)[source]¶
+

Formats a datetime object to a string with format YYYYMMddHHMMSSffff. +If no date is given, the current date is used.

+
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_layout/nepi.util.parsers.html b/doc/sphinx/_build/html/_layout/nepi.util.parsers.html new file mode 100644 index 00000000..c31a65de --- /dev/null +++ b/doc/sphinx/_build/html/_layout/nepi.util.parsers.html @@ -0,0 +1,151 @@ + + + + + + + + nepi.util.parsers package — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

nepi.util.parsers package¶

+
+

Submodules¶

+
+
+

nepi.util.parsers.xml_parser module¶

+
+
+class nepi.util.parsers.xml_parser.ECXMLParser[source]¶
+

Bases: object

+
+
+from_xml(xml)[source]¶
+
+ +
+
+to_xml(ec)[source]¶
+
+ +
+ +
+
+nepi.util.parsers.xml_parser.from_type(value)[source]¶
+
+ +
+
+nepi.util.parsers.xml_parser.to_type(type, value)[source]¶
+
+ +
+
+nepi.util.parsers.xml_parser.xmldecode(s, cast=<type 'str'>)[source]¶
+
+ +
+
+nepi.util.parsers.xml_parser.xmlencode(s)[source]¶
+
+ +
+
+

Module contents¶

+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/index.html b/doc/sphinx/_build/html/_modules/index.html new file mode 100644 index 00000000..976b752e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/index.html @@ -0,0 +1,330 @@ + + + + + + + + Overview: module code — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

All modules for which code is available

+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/data/processing/ccn/parser.html b/doc/sphinx/_build/html/_modules/nepi/data/processing/ccn/parser.html new file mode 100644 index 00000000..57ea0d14 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/data/processing/ccn/parser.html @@ -0,0 +1,505 @@ + + + + + + + + nepi.data.processing.ccn.parser — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.data.processing.ccn.parser

+#!/usr/bin/env python
+
+###############################################################################
+#
+#    CCNX benchmark
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#
+###############################################################################
+
+#
+# This library contains functions to parse (CCNx) ccnd logs.
+#
+# Results from experiments must be stored in a directory
+# named with the experiment run id.
+# ccnd logs are stored in .log files in a subdirectory per node.
+# The following diagram exemplifies the experiment result directory
+# structure (nidi is the unique identifier assigned to node i):
+#
+#    run_id
+#               \   nid1
+#                        \ nid2.log
+#               \   nid2
+#                        \ nid1.log
+#               \   nid3
+#                        \ nid3.log
+#
+
+import collections
+import functools
+import networkx
+import os
+import pickle
+import tempfile
+
+from nepi.util.timefuncs import compute_delay_ms
+from nepi.util.statfuncs import compute_mean
+import nepi.data.processing.ping.parser as ping_parser
+
+
[docs]def is_control(content_name): + return content_name.startswith("ccnx:/%C1") or \ + content_name.startswith("ccnx:/ccnx") or \ + content_name.startswith("ccnx:/...") + +
+
[docs]def parse_file(filename): + """ Parses message information from ccnd log files + + filename: path to ccndlog file + + """ + + faces = dict() + sep = " " + + f = open(filename, "r") + + data = [] + + for line in f: + cols = line.strip().split(sep) + + # CCN_PEEK + # MESSAGE interest_from + # 1374181938.808523 ccnd[9245]: debug.4352 interest_from 6 ccnx:/test/bunny.ts (23 bytes,sim=0CDCC1D7) + # + # MESSAGE interest_to + # 1374181938.812750 ccnd[9245]: debug.3502 interest_to 5 ccnx:/test/bunny.ts (39 bytes,i=2844,sim=0CDCC1D7) + # + # MESSAGE CONTENT FROM + # 1374181938.868682 ccnd[9245]: debug.4643 content_from 5 ccnx:/test/bunny.ts/%FD%05%1E%85%8FVw/%00/%9E%3D%01%D9%3Cn%95%2BvZ%8 + # + # MESSAGE CONTENT_TO + # 1374181938.868772 ccnd[9245]: debug.1619 content_to 6 ccnx:/test/bunny.ts/%FD%05%1E%85%8FVw/%00/%9E%3D%01%D9%3Cn%95%2BvZ%8 + # + # 1375596708.222304 ccnd[9758]: debug.3692 interest_expiry ccnx:/test/bunny.ts/%FD%05%1E%86%B1GS/%00%0A%F7 (44 bytes,c=0:1,i=2819,sim=49FA8048) + + # External face creation + # 1374181452.965961 ccnd[9245]: accepted datagram client id=5 (flags=0x40012) 204.85.191.10 port 9695 + + if line.find("accepted datagram client") > -1: + face_id = (cols[5]).replace("id=",'') + ip = cols[7] + port = cols[9] + faces[face_id] = (ip, port) + continue + + # 1374181452.985296 ccnd[9245]: releasing face id 4 (slot 4) + if line.find("releasing face id") > -1: + face_id = cols[5] + if face_id in faces: + del faces[face_id] + continue + + if len(cols) < 6: + continue + + timestamp = cols[0] + message_type = cols[3] + + if message_type not in ["interest_from", "interest_to", "content_from", + "content_to", "interest_dupnonce", "interest_expiry"]: + continue + + face_id = cols[4] + content_name = cols[5] + + # Interest Nonce ? -> 412A74-0844-0008-50AA-F6EAD4 + nonce = "" + if message_type in ["interest_from", "interest_to", "interest_dupnonce"]: + last = cols[-1] + if len(last.split("-")) == 5: + nonce = last + + try: + size = int((cols[6]).replace('(','')) + except: + print "interest_expiry without face id!", line + continue + + # If no external IP address was identified for this face + # asume it is a local face + peer = "localhost" + + if face_id in faces: + peer, port = faces[face_id] + + data.append((content_name, timestamp, message_type, peer, face_id, + size, nonce, line)) + + f.close() + + return data +
+
[docs]def dump_content_history(content_history): + f = tempfile.NamedTemporaryFile(delete=False) + pickle.dump(content_history, f) + f.close() + return f.name +
+
[docs]def load_content_history(fname): + f = open(fname, "r") + content_history = pickle.load(f) + f.close() + + os.remove(fname) + return content_history +
+
[docs]def annotate_cn_node(graph, nid, ips2nid, data, content_history): + for (content_name, timestamp, message_type, peer, face_id, + size, nonce, line) in data: + + # Ignore control messages for the time being + if is_control(content_name): + continue + + if message_type == "interest_from" and \ + peer == "localhost": + graph.node[nid]["ccn_consumer"] = True + elif message_type == "content_from" and \ + peer == "localhost": + graph.node[nid]["ccn_producer"] = True + + # Ignore local messages for the time being. + # They could later be used to calculate the processing times + # of messages. + if peer == "localhost": + continue + + # remove digest + if message_type in ["content_from", "content_to"]: + content_name = "/".join(content_name.split("/")[:-1]) + + if content_name not in content_history: + content_history[content_name] = list() + + peernid = ips2nid[peer] + graph.add_edge(nid, peernid) + + content_history[content_name].append((timestamp, message_type, nid, + peernid, nonce, size, line)) +
+
[docs]def annotate_cn_graph(logs_dir, graph, parse_ping_logs = False): + """ Adds CCN content history for each node in the topology graph. + + """ + + # Make a copy of the graph to ensure integrity + graph = graph.copy() + + ips2nid = dict() + + for nid in graph.nodes(): + ips = graph.node[nid]["ips"] + for ip in ips: + ips2nid[ip] = nid + + found_files = False + + # Now walk through the ccnd logs... + for dirpath, dnames, fnames in os.walk(logs_dir): + # continue if we are not at the leaf level (if there are subdirectories) + if dnames: + continue + + # Each dirpath correspond to a different node + nid = os.path.basename(dirpath) + + # Cast to numeric nid if necessary + if int(nid) in graph.nodes(): + nid = int(nid) + + content_history = dict() + + for fname in fnames: + if fname.endswith(".log"): + found_files = True + filename = os.path.join(dirpath, fname) + data = parse_file(filename) + annotate_cn_node(graph, nid, ips2nid, data, content_history) + + # Avoid storing everything in memory, instead dump to a file + # and reference the file + fname = dump_content_history(content_history) + graph.node[nid]["history"] = fname + + if not found_files: + msg = "No CCND output files were found to parse at %s " % logs_dir + raise RuntimeError, msg + + if parse_ping_logs: + ping_parser.annotate_cn_graph(logs_dir, graph) + + return graph +
+
[docs]def ccn_producers(graph): + """ Returns the nodes that are content providers """ + return [nid for nid in graph.nodes() \ + if graph.node[nid].get("ccn_producer")] +
+
[docs]def ccn_consumers(graph): + """ Returns the nodes that are content consumers """ + return [nid for nid in graph.nodes() \ + if graph.node[nid].get("ccn_consumer")] +
+
[docs]def process_content_history(graph): + """ Compute CCN message counts and aggregates content historical + information in the content_names dictionary + + """ + + ## Assume single source + source = ccn_consumers(graph)[0] + + interest_expiry_count = 0 + interest_dupnonce_count = 0 + interest_count = 0 + content_count = 0 + content_names = dict() + + # Collect information about exchanged messages by content name and + # link delay info. + for nid in graph.nodes(): + # Load the data collected from the node's ccnd log + fname = graph.node[nid]["history"] + history = load_content_history(fname) + + for content_name in history.keys(): + hist = history[content_name] + + for (timestamp, message_type, nid1, nid2, nonce, size, line) in hist: + if message_type in ["content_from", "content_to"]: + # The first Interest sent will not have a version or chunk number. + # The first Content sent back in reply, will end in /=00 or /%00. + # Make sure to map the first Content to the first Interest. + if content_name.endswith("/=00"): + content_name = "/".join(content_name.split("/")[0:-2]) + + # Add content name to dictionary + if content_name not in content_names: + content_names[content_name] = dict() + content_names[content_name]["interest"] = dict() + content_names[content_name]["content"] = list() + + # Classify interests by replica + if message_type in ["interest_from"] and \ + nonce not in content_names[content_name]["interest"]: + content_names[content_name]["interest"][nonce] = list() + + # Add consumer history + if nid == source: + if message_type in ["interest_to", "content_from"]: + # content name history as seen by the source + if "consumer_history" not in content_names[content_name]: + content_names[content_name]["consumer_history"] = list() + + content_names[content_name]["consumer_history"].append( + (timestamp, message_type)) + + # Add messages per content name and cumulate totals by message type + if message_type == "interest_dupnonce": + interest_dupnonce_count += 1 + elif message_type == "interest_expiry": + interest_expiry_count += 1 + elif message_type == "interest_from": + interest_count += 1 + # Append to interest history of the content name + content_names[content_name]["interest"][nonce].append( + (timestamp, nid2, nid1)) + elif message_type == "content_from": + content_count += 1 + # Append to content history of the content name + content_names[content_name]["content"].append((timestamp, nid2, nid1)) + else: + continue + del hist + del history + + # Compute the time elapsed between the time an interest is sent + # in the consumer node and when the content is received back + for content_name in content_names.keys(): + # order content and interest messages by timestamp + content_names[content_name]["content"] = sorted( + content_names[content_name]["content"]) + + for nonce, timestamps in content_names[content_name][ + "interest"].iteritems(): + content_names[content_name]["interest"][nonce] = sorted( + timestamps) + + history = sorted(content_names[content_name]["consumer_history"]) + content_names[content_name]["consumer_history"] = history + + # compute the rtt time of the message + rtt = None + waiting_content = False + interest_timestamp = None + content_timestamp = None + + for (timestamp, message_type) in history: + if not waiting_content and message_type == "interest_to": + waiting_content = True + interest_timestamp = timestamp + continue + + if waiting_content and message_type == "content_from": + content_timestamp = timestamp + break + + # If we can't determine who sent the interest, discard it + rtt = -1 + if interest_timestamp and content_timestamp: + rtt = compute_delay_ms(content_timestamp, interest_timestamp) + + content_names[content_name]["rtt"] = rtt + content_names[content_name]["lapse"] = (interest_timestamp, content_timestamp) + + return (graph, + content_names, + interest_expiry_count, + interest_dupnonce_count, + interest_count, + content_count) +
+
[docs]def process_content_history_logs(logs_dir, graph, parse_ping_logs = False): + """ Parse CCN logs and aggregate content history information in graph. + Returns annotated graph and message countn and content names history. + + """ + ## Process logs and analyse data + try: + graph = annotate_cn_graph(logs_dir, graph, + parse_ping_logs = parse_ping_logs) + except: + print "Skipping: Error parsing ccnd logs", logs_dir + raise + + source = ccn_consumers(graph)[0] + target = ccn_producers(graph)[0] + + # Process the data from the ccnd logs, but do not re compute + # the link delay. + try: + (graph, + content_names, + interest_expiry_count, + interest_dupnonce_count, + interest_count, + content_count) = process_content_history(graph) + except: + print "Skipping: Error processing ccn data", logs_dir + raise + + return (graph, + content_names, + interest_expiry_count, + interest_dupnonce_count, + interest_count, + content_count)
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/data/processing/ping/parser.html b/doc/sphinx/_build/html/_modules/nepi/data/processing/ping/parser.html new file mode 100644 index 00000000..e69772ad --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/data/processing/ping/parser.html @@ -0,0 +1,212 @@ + + + + + + + + nepi.data.processing.ping.parser — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.data.processing.ping.parser

+#!/usr/bin/env python
+
+###############################################################################
+#
+#    CCNX benchmark
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#
+###############################################################################
+
+#
+# This library contains functions to parse log files generated using ping. 
+#
+
+import collections
+import re
+import os
+
+# RE to match line starting "traceroute to"
+_rre = re.compile("\d+ bytes from ((?P<hostname>[^\s]+) )?\(?(?P<ip>[^\s]+)\)??: icmp_.eq=\d+ ttl=\d+ time=(?P<time>[^\s]+) ms")
+
+
[docs]def parse_file(filename): + """ + filename: path to traceroute file + + """ + + f = open(filename, "r") + + # Traceroute info + target_ip = None + target_hostname = None + + data = [] + + for line in f: + # match traceroute to ... + m = re.match(_rre, line) + if not m: + continue + + target_ip = m.groupdict()["ip"] + # FIX THIS: Make sure the regular expression does not inlcude + # the ')' in the ip group + target_ip = target_ip.replace(")","") + target_hostname = m.groupdict()["hostname"] + time = m.groupdict()["time"] + data.append((target_ip, target_hostname, time)) + + f.close() + + return data +
+
[docs]def annotate_cn_node(graph, nid1, ips2nid, data): + for (target_ip, target_hostname, time) in data: + nid2 = ips2nid[target_ip] + + if "delays" not in graph.edge[nid1][nid2]: + graph.edge[nid1][nid2]["delays"] = [] + + time = float(time.replace("ms", "").replace(" ","")) + + graph.edge[nid1][nid2]["delays"].append(time) +
+
[docs]def annotate_cn_graph(logs_dir, graph): + """ Add delay inormation to graph using data collected using + ping. + + """ + ips2nid = dict() + + for nid in graph.nodes(): + ips = graph.node[nid]["ips"] + for ip in ips: + ips2nid[ip] = nid + + # Walk through the ping logs... + found_files = False + + for dirpath, dnames, fnames in os.walk(logs_dir): + # continue if we are not at the leaf level (if there are subdirectories) + if dnames: + continue + + # Each dirpath correspond to a different host + nid = os.path.basename(dirpath) + + for fname in fnames: + if fname.endswith(".ping"): + found_files = True + filename = os.path.join(dirpath, fname) + data = parse_file(filename) + annotate_cn_node(graph, nid, ips2nid, data) + + if not found_files: + msg = "No PING output files were found to parse at %s " % logs_dir + raise RuntimeError, msg + + # Take as weight the most frequent value + for nid1, nid2 in graph.edges(): + delays = collections.Counter(graph.edge[nid1][nid2]["delays"]) + weight = delays.most_common(1)[0][0] + del graph.edge[nid1][nid2]["delays"] + graph.edge[nid1][nid2]["weight"] = weight + + return graph +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/attribute.html b/doc/sphinx/_build/html/_modules/nepi/execution/attribute.html new file mode 100644 index 00000000..8c87b68b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/attribute.html @@ -0,0 +1,286 @@ + + + + + + + + nepi.execution.attribute — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.execution.attribute

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+### Attribute Types
+
[docs]class Types: + """ Allowed types for the Attribute value + """ + String = "STRING" + Bool = "BOOL" + Enumerate = "ENUM" + Double = "DOUBLE" + Integer = "INTEGER" + +### Attribute Flags
+
[docs]class Flags: + """ Flags to characterize the scope of an Attribute + """ + # 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 = 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 + +
+
[docs]class Attribute(object): + """ An Attribute exposes a configuration parameter of a resource + """ + + def __init__(self, name, help, type = Types.String, + flags = None, default = None, allowed = None, + range = None, set_hook = None): + """ + :param name: Name of the Attribute + :type name: str + + :param help: Description of the Attribute + :type help: str + + :param type: The type expected for the Attribute value. + Should be one of Attribute.Types + :type type: str + + :param flags: Defines Attribute behavior (i.e. whether it is read-only, + read and write, etc). This parameter must take its values from + Attribute.Flags. Flags values can be bitwised + :type flags: hex + + :param default: Default value for the Attribute + :type default: Depends on the type of Attribute + + :param allowed: List of values that the Attribute can take. + This parameter is only meaningful for Enumerate type Attributes + :type allowed: list + + :param range: (max, min) tuple with range of possible values for + Attributes. + This parameter is only meaningful for Integer or Double type + Attributes + :type range: (int, int) or (float, float) + + :param set_hook: Function that will be executed whenever a new + value is set for the Attribute. + :type set_hook: function + + """ + self._name = name + self._help = help + self._type = type + self._flags = flags or 0 + self._allowed = allowed + self._range = range + self._default = self._value = default + # callback to be invoked upon changing the + # attribute value + self.set_hook = set_hook + + @property +
[docs] def name(self): + """ Returns the name of the Attribute """ + return self._name +
+ @property +
[docs] def default(self): + """ Returns the default value of the Attribute """ + return self._default +
+ @property +
[docs] def type(self): + """ Returns the type of the Attribute """ + return self._type +
+ @property +
[docs] def help(self): + """ Returns the description of the Attribute """ + return self._help +
+ @property +
[docs] def flags(self): + """ Returns the flags of the Attribute """ + return self._flags +
+ @property +
[docs] def allowed(self): + """ Returns the set of allowed values for the Attribute """ + return self._allowed +
+ @property +
[docs] def range(self): + """ Returns the range of allowed numerical values for the Attribute """ + return self._range +
+
[docs] def has_flag(self, flag): + """ Returns True if the Attribute has the flag 'flag' + + :param flag: Flag to be checked + :type flag: Flags + """ + return (self._flags & flag) == flag +
+
[docs] def get_value(self): + """ Returns the value of the Attribute """ + return self._value +
+
[docs] def set_value(self, value): + """ Configure a new value for the Attribute """ + valid = True + + if self.type == Types.Enumerate: + valid = value in self._allowed + + 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) + + if valid: + if self.set_hook: + # Hook receives old value, new value + value = self.set_hook(self._value, value) + + self._value = value + else: + raise ValueError("Invalid value %s for attribute %s" % + (str(value), self.name)) +
+ value = property(get_value, set_value) + +
[docs] def is_valid_value(self, value): + """ Attribute subclasses will override this method to add + adequate validation""" + return True +
+ @property +
[docs] def has_changed(self): + """ Returns True if the value has changed from the default """ + return self.value != self.default +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/ec.html b/doc/sphinx/_build/html/_modules/nepi/execution/ec.html new file mode 100644 index 00000000..e95bbc47 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/ec.html @@ -0,0 +1,1365 @@ + + + + + + + + nepi.execution.ec — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.execution.ec

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.util import guid
+from nepi.util.parallel import ParallelRun
+from nepi.util.timefuncs import tnow, tdiffsec, stabsformat, tsformat 
+from nepi.execution.resource import ResourceFactory, ResourceAction, \
+        ResourceState, ResourceState2str
+from nepi.execution.scheduler import HeapScheduler, Task, TaskStatus
+from nepi.execution.trace import TraceAttr
+from nepi.util.serializer import ECSerializer, SFormats
+from nepi.util.plotter import ECPlotter, PFormats
+from nepi.util.netgraph import NetGraph, TopologyType 
+
+# TODO: use multiprocessing instead of threading
+# TODO: Allow to reconnect to a running experiment instance! (reconnect mode vs deploy mode)
+
+import functools
+import logging
+import os
+import sys
+import tempfile
+import time
+import threading
+import weakref
+
+
[docs]class FailureLevel(object): + """ Possible failure states for the experiment """ + OK = 1 + RM_FAILURE = 2 + EC_FAILURE = 3 +
+
[docs]class FailureManager(object): + """ The FailureManager is responsible for handling errors + and deciding whether an experiment should be aborted or not + """ + + def __init__(self): + self._ec = None + self._failure_level = FailureLevel.OK + self._abort = False + +
[docs] def set_ec(self, ec): + self._ec = weakref.ref(ec) +
+ @property +
[docs] def ec(self): + """ Returns the ExperimentController associated to this FailureManager + """ + return self._ec() +
+ @property +
[docs] def abort(self): + return self._abort +
+
[docs] def eval_failure(self, guid): + """ Implements failure policy and sets the abort state of the + experiment based on the failure state and criticality of + the RM + + :param guid: Guid of the RM upon which the failure of the experiment + is evaluated + :type guid: int + + """ + if self._failure_level == FailureLevel.OK: + rm = self.ec.get_resource(guid) + state = rm.state + critical = rm.get("critical") + + if state == ResourceState.FAILED and critical: + self._failure_level = FailureLevel.RM_FAILURE + self._abort = True + self.ec.logger.debug("RM critical failure occurred on guid %d." \ + " Setting EC FAILURE LEVEL to RM_FAILURE" % guid) +
+
[docs] def set_ec_failure(self): + self._failure_level = FailureLevel.EC_FAILURE +
+
[docs]class ECState(object): + """ Possible states of the ExperimentController + + """ + RUNNING = 1 + FAILED = 2 + RELEASED = 3 + TERMINATED = 4 +
+
[docs]class ExperimentController(object): + """ + .. note:: + + An experiment, or scenario, is defined by a concrete set of resources, + and the behavior, configuration and interconnection of those resources. + The Experiment Description (ED) is a detailed representation of a + single experiment. It contains all the necessary information to + allow repeating the experiment. NEPI allows to describe + experiments by registering components (resources), configuring them + and interconnecting them. + + A same experiment (scenario) can be executed many times, generating + different results. We call an experiment execution (instance) a 'run'. + + The ExperimentController (EC), is the entity responsible of + managing an experiment run. The same scenario can be + recreated (and re-run) by instantiating an EC and recreating + the same experiment description. + + An experiment is represented as a graph of interconnected + resources. A resource is a generic concept in the sense that any + component taking part of an experiment, whether physical of + virtual, is considered a resource. A resources could be a host, + a virtual machine, an application, a simulator, a IP address. + + A ResourceManager (RM), is the entity responsible for managing a + single resource. ResourceManagers are specific to a resource + type (i.e. An RM to control a Linux application will not be + the same as the RM used to control a ns-3 simulation). + To support a new type of resource, a new RM must be implemented. + NEPI already provides a variety of RMs to control basic resources, + and new can be extended from the existing ones. + + Through the EC interface the user can create ResourceManagers (RMs), + configure them and interconnect them, to describe an experiment. + Describing an experiment through the EC does not run the experiment. + Only when the 'deploy()' method is invoked on the EC, the EC will take + actions to transform the 'described' experiment into a 'running' experiment. + + While the experiment is running, it is possible to continue to + create/configure/connect RMs, and to deploy them to involve new + resources in the experiment (this is known as 'interactive' deployment). + + An experiments in NEPI is identified by a string id, + which is either given by the user, or automatically generated by NEPI. + The purpose of this identifier is to separate files and results that + belong to different experiment scenarios. + However, since a same 'experiment' can be run many times, the experiment + id is not enough to identify an experiment instance (run). + For this reason, the ExperimentController has two identifier, the + exp_id, which can be re-used in different ExperimentController, + and the run_id, which is unique to one ExperimentController instance, and + is automatically generated by NEPI. + + """ + + @classmethod +
[docs] def load(cls, filepath, format = SFormats.XML): + serializer = ECSerializer() + ec = serializer.load(filepath) + return ec +
+ def __init__(self, exp_id = None, local_dir = None, persist = False, + fm = None, add_node_callback = None, add_edge_callback = None, + **kwargs): + """ ExperimentController entity to model an execute a network + experiment. + + :param exp_id: Human readable name to identify the experiment + :type exp_id: str + + :param local_dir: Path to local directory where to store experiment + related files + :type local_dir: str + + :param persist: Save an XML description of the experiment after + completion at local_dir + :type persist: bool + + :param fm: FailureManager object. If None is given, the default + FailureManager class will be used + :type fm: FailureManager + + :param add_node_callback: Callback to invoke for node instantiation + when automatic topology creation mode is used + :type add_node_callback: function + + :param add_edge_callback: Callback to invoke for edge instantiation + when automatic topology creation mode is used + :type add_edge_callback: function + + """ + super(ExperimentController, self).__init__() + + # Logging + self._logger = logging.getLogger("ExperimentController") + + # Run identifier. It identifies a concrete execution instance (run) + # of an experiment. + # Since a same experiment (same configuration) can be executed many + # times, this run_id permits to separate result files generated on + # different experiment executions + self._run_id = tsformat() + + # Experiment identifier. Usually assigned by the user + # Identifies the experiment scenario (i.e. configuration, + # resources used, etc) + self._exp_id = exp_id or "exp-%s" % os.urandom(8).encode('hex') + + # Local path where to store experiment related files (results, etc) + if not local_dir: + local_dir = tempfile.gettempdir() # /tmp + + self._local_dir = local_dir + self._exp_dir = os.path.join(local_dir, self.exp_id) + self._run_dir = os.path.join(self.exp_dir, self.run_id) + + # If True persist the experiment controller in XML format, after completion + self._persist = persist + + # generator of globally unique ids + self._guid_generator = guid.GuidGenerator() + + # Resource managers + self._resources = dict() + + # Scheduler. It a queue that holds tasks scheduled for + # execution, and yields the next task to be executed + # ordered by execution and arrival time + self._scheduler = HeapScheduler() + + # Tasks + self._tasks = dict() + + # RM groups (for deployment) + self._groups = dict() + + # generator of globally unique id for groups + self._group_id_generator = guid.GuidGenerator() + + # Flag to stop processing thread + self._stop = False + + # Entity in charge of managing system failures + if not fm: + self._fm = FailureManager() + self._fm.set_ec(self) + + # EC state + self._state = ECState.RUNNING + + # Automatically construct experiment description + self._netgraph = None + if add_node_callback or add_edge_callback or kwargs.get("topology"): + self._build_from_netgraph(add_node_callback, add_edge_callback, + **kwargs) + + # The runner is a pool of threads used to parallelize + # execution of tasks + self._nthreads = 20 + self._runner = None + + # Event processing thread + self._cond = threading.Condition() + self._thread = threading.Thread(target = self._process) + self._thread.setDaemon(True) + self._thread.start() + + @property +
[docs] def logger(self): + """ Returns the logger instance of the Experiment Controller + + """ + return self._logger +
+ @property +
[docs] def fm(self): + """ Returns the failure manager + + """ + + return self._fm +
+ @property +
[docs] def failure_level(self): + """ Returns the level of FAILURE of th experiment + + """ + + return self._fm._failure_level +
+ @property +
[docs] def ecstate(self): + """ Returns the state of the Experiment Controller + + """ + return self._state +
+ @property +
[docs] def exp_id(self): + """ Returns the experiment id assigned by the user + + """ + return self._exp_id +
+ @property +
[docs] def run_id(self): + """ Returns the experiment instance (run) identifier (automatically + generated) + + """ + return self._run_id +
+ @property +
[docs] def nthreads(self): + """ Returns the number of processing nthreads used + + """ + return self._nthreads +
+ @property +
[docs] def local_dir(self): + """ Root local directory for experiment files + + """ + return self._local_dir +
+ @property +
[docs] def exp_dir(self): + """ Local directory to store results and other files related to the + experiment. + + """ + return self._exp_dir +
+ @property +
[docs] def run_dir(self): + """ Local directory to store results and other files related to the + experiment run. + + """ + return self._run_dir +
+ @property +
[docs] def persist(self): + """ If True, persists the ExperimentController to XML format upon + experiment completion + + """ + return self._persist +
+ @property +
[docs] def netgraph(self): + """ Return NetGraph instance if experiment description was automatically + generated + + """ + return self._netgraph +
+ @property +
[docs] def abort(self): + """ Returns True if the experiment has failed and should be interrupted, + False otherwise. + + """ + return self._fm.abort +
+
[docs] def inform_failure(self, guid): + """ Reports a failure in a RM to the EC for evaluation + + :param guid: Resource id + :type guid: int + + """ + + return self._fm.eval_failure(guid) +
+
[docs] def wait_finished(self, guids): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state >= STOPPED (i.e. STOPPED, FAILED or + RELEASED ), or until a failure in the experiment occurs + (i.e. abort == True) + + :param guids: List of guids + :type guids: list + + """ + + def quit(): + return self.abort + + return self.wait(guids, state = ResourceState.STOPPED, + quit = quit) +
+
[docs] def wait_started(self, guids): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state >= STARTED, or until a failure in the + experiment occurs (i.e. abort == True) + + :param guids: List of guids + :type guids: list + + """ + + def quit(): + return self.abort + + return self.wait(guids, state = ResourceState.STARTED, + quit = quit) +
+
[docs] def wait_released(self, guids): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state == RELEASED, or until the EC fails + + :param guids: List of guids + :type guids: list + + """ + + def quit(): + return self._state == ECState.FAILED + + return self.wait(guids, state = ResourceState.RELEASED, + quit = quit) +
+
[docs] def wait_deployed(self, guids): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state >= READY, or until a failure in the + experiment occurs (i.e. abort == True) + + :param guids: List of guids + :type guids: list + + """ + + def quit(): + return self.abort + + return self.wait(guids, state = ResourceState.READY, + quit = quit) +
+
[docs] def wait(self, guids, state, quit): + """ Blocking method that waits until all RMs in the 'guids' list + have reached a state >= 'state', or until the 'quit' callback + yields True + + :param guids: List of guids + :type guids: list + + """ + if isinstance(guids, int): + guids = [guids] + + # Make a copy to avoid modifying the original guids list + guids = list(guids) + + while True: + # If there are no more guids to wait for + # or the quit function returns True, exit the loop + if len(guids) == 0 or quit(): + break + + # If a guid reached one of the target states, remove it from list + guid = guids.pop() + rm = self.get_resource(guid) + rstate = rm.state + + if rstate >= state: + self.logger.debug(" %s guid %d DONE - state is %s, required is >= %s " % ( + rm.get_rtype(), guid, rstate, state)) + else: + # Debug... + self.logger.debug(" WAITING FOR guid %d - state is %s, required is >= %s " % ( + guid, rstate, state)) + + guids.append(guid) + + time.sleep(0.5) +
+
[docs] def plot(self, dirpath = None, format= PFormats.FIGURE, show = False): + plotter = ECPlotter() + fpath = plotter.plot(self, dirpath = dirpath, format= format, + show = show) + return fpath +
+
[docs] def serialize(self, format = SFormats.XML): + serializer = ECSerializer() + sec = serializer.load(self, format = format) + return sec +
+
[docs] def save(self, dirpath = None, format = SFormats.XML): + if dirpath == None: + dirpath = self.run_dir + + try: + os.makedirs(dirpath) + except OSError: + pass + + serializer = ECSerializer() + path = serializer.save(self, dirpath, format = format) + return path +
+
[docs] def get_task(self, tid): + """ Returns a task by its id + + :param tid: Id of the task + :type tid: int + + :rtype: Task + + """ + return self._tasks.get(tid) +
+
[docs] def get_resource(self, guid): + """ Returns a registered ResourceManager by its guid + + :param guid: Id of the resource + :type guid: int + + :rtype: ResourceManager + + """ + rm = self._resources.get(guid) + return rm +
+
[docs] def get_resources_by_type(self, rtype): + """ Returns the ResourceManager objects of type rtype + + :param rtype: Resource type + :type rtype: string + + :rtype: list of ResourceManagers + + """ + rms = [] + for guid, rm in self._resources.iteritems(): + if rm.get_rtype() == rtype: + rms.append(rm) + return rms +
+
[docs] def remove_resource(self, guid): + del self._resources[guid] +
+ @property +
[docs] def resources(self): + """ Returns the guids of all ResourceManagers + + :return: Set of all RM guids + :rtype: list + + """ + keys = self._resources.keys() + + return keys +
+
[docs] def filter_resources(self, rtype): + """ Returns the guids of all ResourceManagers of type rtype + + :param rtype: Resource type + :type rtype: string + + :rtype: list of guids + + """ + rms = [] + for guid, rm in self._resources.iteritems(): + if rm.get_rtype() == rtype: + rms.append(rm.guid) + return rms +
+
[docs] def register_resource(self, rtype, guid = None): + """ Registers a new ResourceManager of type 'rtype' in the experiment + + This method will assign a new 'guid' for the RM, if no guid + is specified. + + :param rtype: Type of the RM + :type rtype: str + + :return: Guid of the RM + :rtype: int + + """ + # Get next available guid + guid = self._guid_generator.next(guid) + + # Instantiate RM + rm = ResourceFactory.create(rtype, self, guid) + + # Store RM + self._resources[guid] = rm + + return guid +
+
[docs] def get_attributes(self, guid): + """ Returns all the attributes of the RM with guid 'guid' + + :param guid: Guid of the RM + :type guid: int + + :return: List of attributes + :rtype: list + + """ + rm = self.get_resource(guid) + return rm.get_attributes() +
+
[docs] def get_attribute(self, guid, name): + """ Returns the attribute 'name' of the RM with guid 'guid' + + :param guid: Guid of the RM + :type guid: int + + :param name: Name of the attribute + :type name: str + + :return: The attribute with name 'name' + :rtype: Attribute + + """ + rm = self.get_resource(guid) + return rm.get_attribute(name) +
+
[docs] def register_connection(self, guid1, guid2): + """ Registers a connection between a RM with guid 'guid1' + and another RM with guid 'guid2'. + + The order of the in which the two guids are provided is not + important, since the connection relationship is symmetric. + + :param guid1: First guid to connect + :type guid1: ResourceManager + + :param guid2: Second guid to connect + :type guid: ResourceManager + + """ + rm1 = self.get_resource(guid1) + rm2 = self.get_resource(guid2) + + rm1.register_connection(guid2) + rm2.register_connection(guid1) +
+
[docs] def register_condition(self, guids1, action, guids2, state, + time = None): + """ Registers an action START, STOP or DEPLOY for all RM on list + guids1 to occur at time 'time' after all elements in list guids2 + have reached state 'state'. + + :param guids1: List of guids of RMs subjected to action + :type guids1: list + + :param action: Action to perform (either START, STOP or DEPLOY) + :type action: ResourceAction + + :param guids2: List of guids of RMs to we waited for + :type guids2: list + + :param state: State to wait for on RMs of list guids2 (STARTED, + STOPPED, etc) + :type state: ResourceState + + :param time: Time to wait after guids2 has reached status + :type time: string + + """ + if isinstance(guids1, int): + guids1 = [guids1] + if isinstance(guids2, int): + guids2 = [guids2] + + for guid1 in guids1: + rm = self.get_resource(guid1) + rm.register_condition(action, guids2, state, time) +
+
[docs] def enable_trace(self, guid, name): + """ Enables a trace to be collected during the experiment run + + :param name: Name of the trace + :type name: str + + """ + rm = self.get_resource(guid) + rm.enable_trace(name) +
+
[docs] def trace_enabled(self, guid, name): + """ Returns True if the trace of name 'name' is enabled + + :param name: Name of the trace + :type name: str + + """ + rm = self.get_resource(guid) + return rm.trace_enabled(name) +
+
[docs] def trace(self, guid, name, attr = TraceAttr.ALL, block = 512, offset = 0): + """ Returns information on a collected trace, the trace stream or + blocks (chunks) of the trace stream + + :param name: Name of the trace + :type name: str + + :param attr: Can be one of: + - TraceAttr.ALL (complete trace content), + - TraceAttr.STREAM (block in bytes to read starting + at offset), + - TraceAttr.PATH (full path to the trace file), + - TraceAttr.SIZE (size of trace file). + :type attr: str + + :param block: Number of bytes to retrieve from trace, when attr is + TraceAttr.STREAM + :type name: int + + :param offset: Number of 'blocks' to skip, when attr is TraceAttr.STREAM + :type name: int + + :rtype: str + + """ + rm = self.get_resource(guid) + return rm.trace(name, attr, block, offset) +
+
[docs] def get_traces(self, guid): + """ Returns the list of the trace names of the RM with guid 'guid' + + :param guid: Guid of the RM + :type guid: int + + :return: List of trace names + :rtype: list + + """ + rm = self.get_resource(guid) + return rm.get_traces() + +
+
[docs] def discover(self, guid): + """ Discovers an available resource matching the criteria defined + by the RM with guid 'guid', and associates that resource to the RM + + Not all RM types require (or are capable of) performing resource + discovery. For the RM types which are not capable of doing so, + invoking this method does not have any consequences. + + :param guid: Guid of the RM + :type guid: int + + """ + rm = self.get_resource(guid) + return rm.discover() +
+
[docs] def provision(self, guid): + """ Provisions the resource associated to the RM with guid 'guid'. + + Provisioning means making a resource 'accessible' to the user. + Not all RM types require (or are capable of) performing resource + provisioning. For the RM types which are not capable of doing so, + invoking this method does not have any consequences. + + :param guid: Guid of the RM + :type guid: int + + """ + rm = self.get_resource(guid) + return rm.provision() +
+
[docs] def get(self, guid, name): + """ Returns the value of the attribute with name 'name' on the + RM with guid 'guid' + + :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' + + """ + rm = self.get_resource(guid) + return rm.get(name) +
+
[docs] def set(self, guid, name, value): + """ Modifies the value of the attribute with name 'name' on the + RM with guid 'guid'. + + :param guid: Guid of the RM + :type guid: int + + :param name: Name of the attribute + :type name: str + + :param value: Value of the attribute + + """ + rm = self.get_resource(guid) + rm.set(name, value) +
+
[docs] 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) +
+
[docs] 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) +
+
[docs] def state(self, guid, hr = False): + """ Returns the state of a resource + + :param guid: Resource guid + :type guid: integer + + :param hr: Human readable. Forces return of a + status string instead of a number + :type hr: boolean + + """ + rm = self.get_resource(guid) + state = rm.state + + if hr: + return ResourceState2str.get(state) + + return state +
+
[docs] def stop(self, guid): + """ Stops the RM with guid 'guid' + + Stopping a RM means that the resource it controls will + no longer take part of the experiment. + + :param guid: Guid of the RM + :type guid: int + + """ + rm = self.get_resource(guid) + return rm.stop() +
+
[docs] def start(self, guid): + """ Starts the RM with guid 'guid' + + Starting a RM means that the resource it controls will + begin taking part of the experiment. + + :param guid: Guid of the RM + :type guid: int + + """ + rm = self.get_resource(guid) + return rm.start() +
+
[docs] 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 +
+
[docs] 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 +
+
[docs] 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 +
+
[docs] 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 +
+
[docs] 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 +
+
[docs] 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 +
+
[docs] 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 +
+
[docs] def set_with_conditions(self, name, value, guids1, guids2, state, + time = None): + """ Modifies the value of attribute with name 'name' on all RMs + on the guids1 list when time 'time' has elapsed since all + elements in guids2 list have reached state 'state'. + + :param name: Name of attribute to set in RM + :type name: string + + :param value: Value of attribute to set in RM + :type name: string + + :param guids1: List of guids of RMs subjected to action + :type guids1: list + + :param action: Action to register (either START or STOP) + :type action: ResourceAction + + :param guids2: List of guids of RMs to we waited for + :type guids2: list + + :param state: State to wait for on RMs (STARTED, STOPPED, etc) + :type state: ResourceState + + :param time: Time to wait after guids2 has reached status + :type time: string + + """ + if isinstance(guids1, int): + guids1 = [guids1] + if isinstance(guids2, int): + guids2 = [guids2] + + for guid1 in guids1: + rm = self.get_resource(guid) + rm.set_with_conditions(name, value, guids2, state, time) +
+
[docs] def deploy(self, guids = None, wait_all_ready = True, group = None): + """ Deploys all ResourceManagers in the guids list. + + If the argument 'guids' is not given, all RMs with state NEW + are deployed. + + :param guids: List of guids of RMs to deploy + :type guids: list + + :param wait_all_ready: Wait until all RMs are ready in + order to start the RMs + :type guid: int + + :param group: Id of deployment group in which to deploy RMs + :type group: int + + """ + self.logger.debug(" ------- DEPLOY START ------ ") + + if not guids: + # If no guids list was passed, all 'NEW' RMs will be deployed + guids = [] + for guid, rm in self._resources.iteritems(): + if rm.state == ResourceState.NEW: + guids.append(guid) + + if isinstance(guids, int): + guids = [guids] + + # Create deployment group + # New guids can be added to a same deployment group later on + new_group = False + if not group: + new_group = True + group = self._group_id_generator.next() + + if group not in self._groups: + self._groups[group] = [] + + self._groups[group].extend(guids) + + def wait_all_and_start(group): + # Function that checks if all resources are READY + # before scheduling a start_with_conditions for each RM + reschedule = False + + # Get all guids in group + guids = self._groups[group] + + for guid in guids: + if self.state(guid) < ResourceState.READY: + reschedule = True + break + + if reschedule: + callback = functools.partial(wait_all_and_start, group) + self.schedule("1s", callback) + else: + # If all resources are ready, we schedule the start + for guid in guids: + 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. + # This aims at reducing the number of tasks looping in the + # scheduler. + # Instead of having many start tasks, we will have only one for + # the whole group. + callback = functools.partial(wait_all_and_start, group) + self.schedule("0s", callback) + + for guid in guids: + rm = self.get_resource(guid) + rm.deployment_group = group + self.schedule("0s", rm.deploy_with_conditions) + + 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) +
+
[docs] def release(self, guids = None): + """ Releases all ResourceManagers in the guids list. + + If the argument 'guids' is not given, all RMs registered + in the experiment are released. + + :param guids: List of RM guids + :type guids: list + + """ + if self._state == ECState.RELEASED: + return + + if isinstance(guids, int): + guids = [guids] + + if not guids: + guids = self.resources + + for guid in guids: + rm = self.get_resource(guid) + self.schedule("0s", rm.release) + + self.wait_released(guids) + + if self.persist: + self.save() + + for guid in guids: + if self.get(guid, "hardRelease"): + self.remove_resource(guid)\ + + # Mark the EC state as RELEASED + self._state = ECState.RELEASED +
+
[docs] def shutdown(self): + """ Releases all resources and stops the ExperimentController + + """ + # If there was a major failure we can't exit gracefully + 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 + self._state = ECState.TERMINATED + + # Stop processing thread + self._stop = True + + # Notify condition to wake up the processing thread + self._notify() + + if self._thread.is_alive(): + self._thread.join() +
+
[docs] def schedule(self, date, callback, track = False): + """ Schedules a callback to be executed at time 'date'. + + :param date: string containing execution time for the task. + It can be expressed as an absolute time, using + timestamp format, or as a relative time matching + ^\d+.\d+(h|m|s|ms|us)$ + + :param callback: code to be executed for the task. Must be a + Python function, and receives args and kwargs + as arguments. + + :param track: if set to True, the task will be retrievable with + the get_task() method + + :return : The Id of the task + :rtype: int + + """ + timestamp = stabsformat(date) + task = Task(timestamp, callback) + task = self._scheduler.schedule(task) + + if track: + self._tasks[task.id] = task + + # Notify condition to wake up the processing thread + self._notify() + + return task.id +
+ def _process(self): + """ Process scheduled tasks. + + .. note:: + + Tasks are scheduled by invoking the schedule method with a target + callback and an execution time. + The schedule method creates a new Task object with that callback + and execution time, and pushes it into the '_scheduler' queue. + The execution time and the order of arrival of tasks are used + to order the tasks in the queue. + + The _process method is executed in an independent thread held by + the ExperimentController for as long as the experiment is running. + This method takes tasks from the '_scheduler' queue in a loop + and processes them in parallel using multithreading. + The environmental variable NEPI_NTHREADS can be used to control + the number of threads used to process tasks. The default value is + 50. + + To execute tasks in parallel, a ParallelRunner (PR) object is used. + This object keeps a pool of threads (workers), and a queue of tasks + scheduled for 'immediate' execution. + + On each iteration, the '_process' loop will take the next task that + is scheduled for 'future' execution from the '_scheduler' queue, + and if the execution time of that task is >= to the current time, + it will push that task into the PR for 'immediate execution'. + As soon as a worker is free, the PR will assign the next task to + that worker. + + Upon receiving a task to execute, each PR worker (thread) will + invoke the _execute method of the EC, passing the task as + argument. + The _execute method will then invoke task.callback inside a + try/except block. If an exception is raised by the tasks.callback, + it will be trapped by the try block, logged to standard error + (usually the console), and the task will be marked as failed. + + """ + + self._nthreads = int(os.environ.get("NEPI_NTHREADS", str(self._nthreads))) + self._runner = ParallelRun(maxthreads = self.nthreads) + self._runner.start() + + while not self._stop: + try: + self._cond.acquire() + + task = self._scheduler.next() + + if not task: + # No task to execute. Wait for a new task to be scheduled. + self._cond.wait() + else: + # The task timestamp is in the future. Wait for timeout + # or until another task is scheduled. + now = tnow() + if now < task.timestamp: + # Calculate timeout in seconds + timeout = tdiffsec(task.timestamp, now) + + # Re-schedule task with the same timestamp + self._scheduler.schedule(task) + + task = None + + # Wait timeout or until a new task awakes the condition + self._cond.wait(timeout) + + self._cond.release() + + if task: + # Process tasks in parallel + self._runner.put(self._execute, task) + except: + import traceback + err = traceback.format_exc() + self.logger.error("Error while processing tasks in the EC: %s" % err) + + # Set the EC to FAILED state + self._state = ECState.FAILED + + # Set the FailureManager failure level to EC failure + self._fm.set_ec_failure() + + self.logger.debug("Exiting the task processing loop ... ") + + self._runner.sync() + self._runner.destroy() + + def _execute(self, task): + """ Executes a single task. + + :param task: Object containing the callback to execute + :type task: Task + + """ + try: + # Invoke callback + task.result = task.callback() + task.status = TaskStatus.DONE + except: + import traceback + err = traceback.format_exc() + task.result = err + task.status = TaskStatus.ERROR + + self.logger.error("Error occurred while executing task: %s" % err) + + def _notify(self): + """ Awakes the processing thread if it is blocked waiting + for new tasks to arrive + + """ + self._cond.acquire() + self._cond.notify() + self._cond.release() + + def _build_from_netgraph(self, add_node_callback, add_edge_callback, + **kwargs): + """ Automates experiment description using a NetGraph instance. + """ + self._netgraph = NetGraph(**kwargs) + + if add_node_callback: + ### Add resources to the EC + for nid in self.netgraph.nodes(): + add_node_callback(self, nid) + + if add_edge_callback: + #### Add connections between resources + for nid1, nid2 in self.netgraph.edges(): + add_edge_callback(self, nid1, nid2) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/resource.html b/doc/sphinx/_build/html/_modules/nepi/execution/resource.html new file mode 100644 index 00000000..dd535d73 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/resource.html @@ -0,0 +1,1326 @@ + + + + + + + + nepi.execution.resource — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.execution.resource

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.util.timefuncs import tnow, tdiff, tdiffsec, stabsformat
+from nepi.util.logger import Logger
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.trace import TraceAttr
+
+import copy
+import functools
+import logging
+import os
+import pkgutil
+import sys
+import threading
+import weakref
+
+
[docs]class ResourceAction: + """ Action that a user can order to a Resource Manager + + """ + DEPLOY = 0 + START = 1 + STOP = 2 +
+
[docs]class ResourceState: + """ State of a Resource Manager + + """ + NEW = 0 + DISCOVERED = 1 + RESERVED = 2 + PROVISIONED = 3 + READY = 4 + STARTED = 5 + STOPPED = 6 + FAILED = 7 + RELEASED = 8 +
+ResourceState2str = dict({ + ResourceState.NEW : "NEW", + ResourceState.DISCOVERED : "DISCOVERED", + ResourceState.RESERVED : "RESERVED", + ResourceState.PROVISIONED : "PROVISIONED", + ResourceState.READY : "READY", + ResourceState.STARTED : "STARTED", + ResourceState.STOPPED : "STOPPED", + ResourceState.FAILED : "FAILED", + ResourceState.RELEASED : "RELEASED", + }) + +
[docs]def clsinit(cls): + """ Initializes template information (i.e. attributes and traces) + on classes derived from the ResourceManager class. + + It is used as a decorator in the class declaration as follows: + + @clsinit + class MyResourceManager(ResourceManager): + + ... + + """ + + cls._clsinit() + return cls +
+
[docs]def clsinit_copy(cls): + """ Initializes template information (i.e. attributes and traces) + on classes derived from the ResourceManager class. + It differs from the clsinit method in that it forces inheritance + of attributes and traces from the parent class. + + It is used as a decorator in the class declaration as follows: + + @clsinit + class MyResourceManager(ResourceManager): + + ... + + + clsinit_copy should be prefered to clsinit when creating new + ResourceManager child classes. + + """ + + cls._clsinit_copy() + return cls +
+
[docs]def failtrap(func): + """ Decorator function for instance methods that should set the + RM state to FAILED when an error is raised. The methods that must be + decorated are: discover, reserved, provision, deploy, start, stop. + + """ + def wrapped(self, *args, **kwargs): + try: + return func(self, *args, **kwargs) + except: + self.fail() + + import traceback + err = traceback.format_exc() + logger = Logger(self._rtype) + logger.error(err) + logger.error("SETTING guid %d to state FAILED" % self.guid) + raise + + return wrapped +
+@clsinit +
[docs]class ResourceManager(Logger): + """ Base clase for all ResourceManagers. + + A ResourceManger is specific to a resource type (e.g. Node, + Switch, Application, etc) on a specific platform (e.g. PlanetLab, + OMF, etc). + + The ResourceManager instances are responsible for interacting with + and controlling concrete (physical or virtual) resources in the + experimental platforms. + + """ + _rtype = "Resource" + _attributes = None + _traces = None + _help = None + _platform = None + _reschedule_delay = "0.5s" + + @classmethod + def _register_attribute(cls, attr): + """ Resource subclasses will invoke this method to add a + resource attribute + + """ + + cls._attributes[attr.name] = attr + + @classmethod + def _remove_attribute(cls, name): + """ Resource subclasses will invoke this method to remove a + resource attribute + + """ + + del cls._attributes[name] + + @classmethod + def _register_trace(cls, trace): + """ Resource subclasses will invoke this method to add a + resource trace + + """ + + cls._traces[trace.name] = trace + + @classmethod + def _remove_trace(cls, name): + """ Resource subclasses will invoke this method to remove a + resource trace + + """ + + del cls._traces[name] + + @classmethod + def _register_attributes(cls): + """ Resource subclasses will invoke this method to register + resource attributes. + + This method should be overriden in the RMs that define + 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.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): + """ Resource subclasses will invoke this method to register + resource traces + + This method should be overridden in the RMs that define traces. + + """ + + pass + + @classmethod + def _clsinit(cls): + """ ResourceManager classes have different attributes and traces. + Attribute and traces are stored in 'class attribute' dictionaries. + When a new ResourceManager class is created, the _clsinit method is + called to create a new instance of those dictionaries and initialize + them. + + The _clsinit method is called by the clsinit decorator method. + + """ + + # static template for resource attributes + cls._attributes = dict() + cls._register_attributes() + + # static template for resource traces + cls._traces = dict() + cls._register_traces() + + @classmethod + def _clsinit_copy(cls): + """ Same as _clsinit, except that after creating new instances of the + dictionaries it copies all the attributes and traces from the parent + class. + + The _clsinit_copy method is called by the clsinit_copy decorator method. + + """ + # static template for resource attributes + cls._attributes = copy.deepcopy(cls._attributes) + cls._register_attributes() + + # static template for resource traces + cls._traces = copy.deepcopy(cls._traces) + cls._register_traces() + + @classmethod +
[docs] def get_rtype(cls): + """ Returns the type of the Resource Manager + + """ + return cls._rtype +
+ @classmethod +
[docs] def get_attributes(cls): + """ Returns a copy of the attributes + + """ + return copy.deepcopy(cls._attributes.values()) +
+ @classmethod +
[docs] def get_attribute(cls, name): + """ Returns a copy of the attribute with name 'name' + + """ + return copy.deepcopy(cls._attributes[name]) +
+ @classmethod +
[docs] def get_traces(cls): + """ Returns a copy of the traces + + """ + return copy.deepcopy(cls._traces.values()) +
+ @classmethod +
[docs] def get_help(cls): + """ Returns the description of the type of Resource + + """ + return cls._help +
+ @classmethod +
[docs] def get_platform(cls): + """ Returns the identified of the platform (i.e. testbed type) + for the Resource + + """ + return cls._platform +
+ @classmethod +
[docs] 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 +
[docs] 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()) + + self._guid = guid + self._ec = weakref.ref(ec) + self._connections = set() + self._conditions = dict() + + # the resource instance gets a copy of all attributes + self._attrs = copy.deepcopy(self._attributes) + + # the resource instance gets a copy of all traces + self._trcs = copy.deepcopy(self._traces) + + # Each resource is placed on a deployment group by the EC + # during deployment + self.deployment_group = None + + self._start_time = None + self._stop_time = None + self._discover_time = None + self._reserved_time = None + self._provision_time = None + self._ready_time = None + self._release_time = None + self._failed_time = None + + self._state = ResourceState.NEW + + # instance lock to synchronize exclusive state change methods (such + # as deploy and release methods), in order to prevent them from being + # executed at the same time and corrupt internal resource state + self._release_lock = threading.Lock() + + @property +
[docs] def guid(self): + """ Returns the global unique identifier of the RM """ + return self._guid +
+ @property +
[docs] def ec(self): + """ Returns the Experiment Controller of the RM """ + return self._ec() +
+ @property +
[docs] def connections(self): + """ Returns the set of guids of connected RMs """ + return self._connections +
+ @property +
[docs] def conditions(self): + """ Returns the conditions to which the RM is subjected to. + + This method returns a dictionary of conditions lists indexed by + a ResourceAction. + + """ + return self._conditions +
+ @property +
[docs] def start_time(self): + """ Returns the start time of the RM as a timestamp """ + return self._start_time +
+ @property +
[docs] def stop_time(self): + """ Returns the stop time of the RM as a timestamp """ + return self._stop_time +
+ @property +
[docs] def discover_time(self): + """ Returns the discover time of the RM as a timestamp """ + return self._discover_time +
+ @property +
[docs] def reserved_time(self): + """ Returns the reserved time of the RM as a timestamp """ + return self._reserved_time +
+ @property +
[docs] def provision_time(self): + """ Returns the provision time of the RM as a timestamp """ + return self._provision_time +
+ @property +
[docs] def ready_time(self): + """ Returns the deployment time of the RM as a timestamp """ + return self._ready_time +
+ @property +
[docs] def release_time(self): + """ Returns the release time of the RM as a timestamp """ + return self._release_time +
+ @property +
[docs] def failed_time(self): + """ Returns the time failure occurred for the RM as a timestamp """ + return self._failed_time +
+ @property +
[docs] def state(self): + """ Get the current state of the RM """ + return self._state +
+ @property +
[docs] def reschedule_delay(self): + """ Returns default reschedule delay """ + return self._reschedule_delay +
+
[docs] def log_message(self, msg): + """ Returns the log message formatted with added information. + + :param msg: text message + :type msg: str + :rtype: str + + """ + return " %s guid %d - %s " % (self._rtype, self.guid, msg) +
+
[docs] def register_connection(self, guid): + """ Registers a connection to the RM identified by guid + + This method should not be overridden. Specific functionality + should be added in the do_connect method. + + :param guid: Global unique identified of the RM to connect to + :type guid: int + + """ + if self.valid_connection(guid): + self.do_connect(guid) + self._connections.add(guid) +
+
[docs] def unregister_connection(self, guid): + """ Removes a registered connection to the RM identified by guid + + This method should not be overridden. Specific functionality + should be added in the do_disconnect method. + + :param guid: Global unique identified of the RM to connect to + :type guid: int + + """ + if guid in self._connections: + self.do_disconnect(guid) + self._connections.remove(guid) +
+ @failtrap +
[docs] def discover(self): + """ Performs resource discovery. + + This method is responsible for selecting an individual resource + matching user requirements. + + This method should not be overridden directly. Specific functionality + should be added in the do_discover method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_discover() +
+ @failtrap +
[docs] def reserve(self): + """ Performs resource reserve. + + This method is responsible for reserving an individual resource + matching user requirements. + + This method should not be overridden directly. Specific functionality + should be added in the do_reserved method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_reserve() +
+ @failtrap +
[docs] def provision(self): + """ Performs resource provisioning. + + This method is responsible for provisioning one resource. + After this method has been successfully invoked, the resource + should be accessible/controllable by the RM. + + This method should not be overridden directly. Specific functionality + should be added in the do_provision method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_provision() +
+ @failtrap +
[docs] def configure(self): + """ Performs resource configuration. + + This method is responsible for configuring one resource. + After this method has been successfully invoked, the resource + should be set up to start the experimentation. + + This method should not be overridden directly. Specific functionality + should be added in the do_configure method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_configure() +
+ @failtrap +
[docs] def start(self): + """ Starts the RM (e.g. launch remote process). + + There is no standard start behavior. Some RMs will not need to perform + any actions upon start. + + This method should not be overridden directly. Specific functionality + should be added in the do_start method. + + """ + + if not self.state in [ResourceState.READY, ResourceState.STOPPED]: + self.error("Wrong state %s for start" % self.state) + return + + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_start() +
+ @failtrap +
[docs] def stop(self): + """ Interrupts the RM, stopping any tasks the RM was performing. + + There is no standard stop behavior. Some RMs will not need to perform + any actions upon stop. + + This method should not be overridden directly. Specific functionality + should be added in the do_stop method. + + """ + if not self.state in [ResourceState.STARTED]: + self.error("Wrong state %s for stop" % self.state) + return + + with self._release_lock: + self.do_stop() +
+ @failtrap +
[docs] def deploy(self): + """ Execute all steps required for the RM to reach the state READY. + + This method is responsible for deploying the resource (and invoking + the discover and provision methods). + + This method should not be overridden directly. Specific functionality + should be added in the do_deploy method. + + """ + if self.state > ResourceState.READY: + self.error("Wrong state %s for deploy" % self.state) + return + + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_deploy() +
+
[docs] def release(self): + """ Perform actions to free resources used by the RM. + + This method is responsible for releasing resources that were + used during the experiment by the RM. + + This method should not be overridden directly. Specific functionality + should be added in the do_release method. + + """ + with self._release_lock: + try: + self.do_release() + except: + self.set_released() + + import traceback + err = traceback.format_exc() + msg = " %s guid %d ----- FAILED TO RELEASE ----- \n %s " % ( + self._rtype, self.guid, err) + logger = Logger(self._rtype) + logger.debug(msg) +
+
[docs] def fail(self): + """ Sets the RM to state FAILED. + + This method should not be overridden directly. Specific functionality + should be added in the do_fail method. + + """ + with self._release_lock: + if self._state != ResourceState.RELEASED: + self.do_fail() +
+
[docs] def set(self, name, value): + """ Set the value of the attribute + + :param name: Name of the attribute + :type name: str + :param name: Value of the attribute + :type name: str + """ + attr = self._attrs[name] + attr.value = value + return value +
+
[docs] def get(self, name): + """ Returns the value of the attribute + + :param name: Name of the attribute + :type name: str + :rtype: str + """ + attr = self._attrs[name] + + """ + A.Q. Commenting due to performance impact + if attr.has_flag(Flags.Global): + self.warning( "Attribute %s is global. Use get_global instead." % name) + """ + + return attr.value +
+
[docs] 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 +
+
[docs] 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) +
+
[docs] 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 +
+
[docs] def enable_trace(self, name): + """ Explicitly enable trace generation + + :param name: Name of the trace + :type name: str + """ + trace = self._trcs[name] + trace.enabled = True +
+
[docs] def trace_enabled(self, name): + """Returns True if trace is enables + + :param name: Name of the trace + :type name: str + """ + trace = self._trcs[name] + return trace.enabled +
+
[docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + """ Get information on collected trace + + :param name: Name of the trace + :type name: str + + :param attr: Can be one of: + - TraceAttr.ALL (complete trace content), + - TraceAttr.STREAM (block in bytes to read starting at offset), + - TraceAttr.PATH (full path to the trace file), + - TraceAttr.SIZE (size of trace file). + :type attr: str + + :param block: Number of bytes to retrieve from trace, when attr is TraceAttr.STREAM + :type name: int + + :param offset: Number of 'blocks' to skip, when attr is TraceAttr.STREAM + :type name: int + + :rtype: str + """ + pass +
+
[docs] def register_condition(self, action, group, state, time = None): + """ Registers a condition on the resource manager to allow execution + of 'action' only after 'time' has elapsed from the moment all resources + in 'group' reached state 'state' + + :param action: Action to restrict to condition (either 'START' or 'STOP') + :type action: str + :param group: Group of RMs to wait for (list of guids) + :type group: int or list of int + :param state: State to wait for on all RM in group. (either 'STARTED', 'STOPPED' or 'READY') + :type state: str + :param time: Time to wait after 'state' is reached on all RMs in group. (e.g. '2s') + :type time: str + + """ + + if not action in self.conditions: + self._conditions[action] = list() + + conditions = self.conditions.get(action) + + # For each condition to register a tuple of (group, state, time) is + # added to the 'action' list + if not isinstance(group, list): + group = [group] + + conditions.append((group, state, time)) +
+
[docs] def unregister_condition(self, group, action = None): + """ Removed conditions for a certain group of guids + + :param action: Action to restrict to condition (either 'START', 'STOP' or 'READY') + :type action: str + + :param group: Group of RMs to wait for (list of guids) + :type group: int or list of int + + """ + # For each condition a tuple of (group, state, time) is + # added to the 'action' list + if not isinstance(group, list): + group = [group] + + for act, conditions in self.conditions.iteritems(): + if action and act != action: + continue + + for condition in list(conditions): + (grp, state, time) = condition + + # If there is an intersection between grp and group, + # then remove intersected elements + intsec = set(group).intersection(set(grp)) + if intsec: + idx = conditions.index(condition) + newgrp = set(grp) + newgrp.difference_update(intsec) + conditions[idx] = (newgrp, state, time) +
+
[docs] def get_connected(self, rtype = None): + """ Returns the list of RM with the type 'rtype' + + :param rtype: Type of the RM we look for + :type rtype: str + :return: list of guid + """ + 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) + return connected +
+
[docs] def is_rm_instance(self, rtype): + """ Returns True if the RM is instance of 'rtype' + + :param rtype: Type of the RM we look for + :type rtype: str + :return: True|False + """ + rclass = ResourceFactory.get_resource_type(rtype) + if isinstance(self, rclass): + return True + return False +
+ @failtrap + def _needs_reschedule(self, group, state, time): + """ Internal method that verify if 'time' has elapsed since + all elements in 'group' have reached state 'state'. + + :param group: Group of RMs to wait for (list of guids) + :type group: int or list of int + :param state: State to wait for on all RM in group. (either 'STARTED', 'STOPPED' or 'READY') + :type state: str + :param time: Time to wait after 'state' is reached on all RMs in group. (e.g. '2s') + :type time: str + + .. note : time should be written like "2s" or "3m" with s for seconds, m for minutes, h for hours, ... + If for example, you need to wait 2min 30sec, time could be "150s" or "2.5m". + For the moment, 2m30s is not a correct syntax. + + """ + reschedule = False + delay = self.reschedule_delay + + # check state and time elapsed on all RMs + for guid in group: + rm = self.ec.get_resource(guid) + + # If one of the RMs this resource needs to wait for has FAILED + # and is critical we raise an exception + if rm.state == ResourceState.FAILED: + if not rm.get('critical'): + continue + msg = "Resource can not wait for FAILED RM %d. Setting Resource to FAILED" + raise RuntimeError, msg + + # If the RM state is lower than the requested state we must + # reschedule (e.g. if RM is READY but we required STARTED). + if rm.state < state: + reschedule = True + break + + # If there is a time restriction, we must verify the + # restriction is satisfied + if time: + if state == ResourceState.DISCOVERED: + t = rm.discover_time + elif state == ResourceState.RESERVED: + t = rm.reserved_time + elif state == ResourceState.PROVISIONED: + t = rm.provision_time + elif state == ResourceState.READY: + t = rm.ready_time + elif state == ResourceState.STARTED: + t = rm.start_time + elif state == ResourceState.STOPPED: + t = rm.stop_time + elif state == ResourceState.RELEASED: + t = rm.release_time + else: + break + + # time already elapsed since RM changed state + waited = "%fs" % tdiffsec(tnow(), t) + + # time still to wait + wait = tdiffsec(stabsformat(time), stabsformat(waited)) + + if wait > 0.001: + reschedule = True + delay = "%fs" % wait + break + + return reschedule, delay + +
[docs] def set_with_conditions(self, name, value, group, state, time): + """ Set value 'value' on attribute with name 'name' when 'time' + has elapsed since all elements in 'group' have reached state + 'state' + + :param name: Name of the attribute to set + :type name: str + :param name: Value of the attribute to set + :type name: str + :param group: Group of RMs to wait for (list of guids) + :type group: int or list of int + :param state: State to wait for on all RM in group. (either 'STARTED', 'STOPPED' or 'READY') + :type state: str + :param time: Time to wait after 'state' is reached on all RMs in group. (e.g. '2s') + :type time: str + """ + + reschedule = False + delay = self.reschedule_delay + + ## evaluate if set conditions are met + + # only can set with conditions after the RM is started + if self.state != ResourceState.STARTED: + reschedule = True + else: + reschedule, delay = self._needs_reschedule(group, state, time) + + if reschedule: + callback = functools.partial(self.set_with_conditions, + name, value, group, state, time) + self.ec.schedule(delay, callback) + else: + self.set(name, value) +
+
[docs] def start_with_conditions(self): + """ Starts RM when all the conditions in self.conditions for + action 'START' are satisfied. + + """ + #import pdb;pdb.set_trace() + + reschedule = False + delay = self.reschedule_delay + + + ## evaluate if conditions to start are met + if self.ec.abort: + return + + # Can only start when RM is either STOPPED or READY + if self.state not in [ResourceState.STOPPED, ResourceState.READY]: + reschedule = True + self.debug("---- RESCHEDULING START ---- state %s " % self.state ) + else: + start_conditions = self.conditions.get(ResourceAction.START, []) + + self.debug("---- START CONDITIONS ---- %s" % start_conditions) + + # Verify all start conditions are met + for (group, state, time) in start_conditions: + # Uncomment for debug + #unmet = [] + #for guid in group: + # rm = self.ec.get_resource(guid) + # unmet.append((guid, rm._state)) + # + #self.debug("---- WAITED STATES ---- %s" % unmet ) + + reschedule, delay = self._needs_reschedule(group, state, time) + if reschedule: + break + + if reschedule: + self.ec.schedule(delay, self.start_with_conditions) + else: + self.debug("----- STARTING ---- ") + self.start() +
+
[docs] def stop_with_conditions(self): + """ Stops RM when all the conditions in self.conditions for + action 'STOP' are satisfied. + + """ + reschedule = False + delay = self.reschedule_delay + + ## evaluate if conditions to stop are met + if self.ec.abort: + return + + # only can stop when RM is STARTED + if self.state != ResourceState.STARTED: + reschedule = True + self.debug("---- RESCHEDULING STOP ---- state %s " % self.state ) + else: + self.debug(" ---- STOP CONDITIONS ---- %s" % + self.conditions.get(ResourceAction.STOP)) + + stop_conditions = self.conditions.get(ResourceAction.STOP, []) + for (group, state, time) in stop_conditions: + reschedule, delay = self._needs_reschedule(group, state, time) + if reschedule: + break + + if reschedule: + callback = functools.partial(self.stop_with_conditions) + self.ec.schedule(delay, callback) + else: + self.debug(" ----- STOPPING ---- ") + self.stop() +
+
[docs] def deploy_with_conditions(self): + """ Deploy RM when all the conditions in self.conditions for + action 'READY' are satisfied. + + """ + reschedule = False + delay = self.reschedule_delay + + ## evaluate if conditions to deploy are met + if self.ec.abort: + return + + # only can deploy when RM is either NEW, DISCOVERED or PROVISIONED + if self.state not in [ResourceState.NEW, ResourceState.DISCOVERED, + ResourceState.RESERVED, ResourceState.PROVISIONED]: + #### XXX: A.Q. IT SHOULD FAIL IF DEPLOY IS CALLED IN OTHER STATES! + reschedule = True + self.debug("---- RESCHEDULING DEPLOY ---- state %s " % self.state ) + else: + deploy_conditions = self.conditions.get(ResourceAction.DEPLOY, []) + + self.debug("---- DEPLOY CONDITIONS ---- %s" % deploy_conditions) + + # Verify all start conditions are met + for (group, state, time) in deploy_conditions: + # Uncomment for debug + #unmet = [] + #for guid in group: + # rm = self.ec.get_resource(guid) + # unmet.append((guid, rm._state)) + + #self.debug("---- WAITED STATES ---- %s" % unmet ) + + reschedule, delay = self._needs_reschedule(group, state, time) + if reschedule: + break + + if reschedule: + self.ec.schedule(delay, self.deploy_with_conditions) + else: + self.debug("----- DEPLOYING ---- ") + self.deploy() +
+
[docs] def do_connect(self, guid): + """ Performs actions that need to be taken upon associating RMs. + This method should be redefined when necessary in child classes. + """ + pass +
+
[docs] def do_disconnect(self, guid): + """ Performs actions that need to be taken upon disassociating RMs. + This method should be redefined when necessary in child classes. + """ + pass +
+
[docs] def valid_connection(self, guid): + """Checks whether a connection with the other RM + is valid. + This method need to be redefined by each new Resource Manager. + + :param guid: Guid of the current Resource Manager + :type guid: int + :rtype: Boolean + + """ + # TODO: Validate! + return True +
+
[docs] def do_discover(self): + self.set_discovered() +
+
[docs] def do_reserve(self): + self.set_reserved() +
+
[docs] def do_provision(self): + self.set_provisioned() +
+
[docs] def do_configure(self): + pass +
+
[docs] def do_start(self): + self.set_started() +
+
[docs] def do_stop(self): + self.set_stopped() +
+
[docs] def do_deploy(self): + self.set_ready() +
+
[docs] def do_release(self): + self.set_released() +
+
[docs] def do_fail(self): + self.set_failed() + self.ec.inform_failure(self.guid) +
+
[docs] def set_started(self, time = None): + """ Mark ResourceManager as STARTED """ + self.set_state(ResourceState.STARTED, "_start_time", time) + self.debug("----- STARTED ---- ") +
+
[docs] def set_stopped(self, time = None): + """ Mark ResourceManager as STOPPED """ + self.set_state(ResourceState.STOPPED, "_stop_time", time) + self.debug("----- STOPPED ---- ") +
+
[docs] def set_ready(self, time = None): + """ Mark ResourceManager as READY """ + self.set_state(ResourceState.READY, "_ready_time", time) + self.debug("----- READY ---- ") +
+
[docs] def set_released(self, time = None): + """ Mark ResourceManager as REALEASED """ + self.set_state(ResourceState.RELEASED, "_release_time", time) + + msg = " %s guid %d ----- RELEASED ----- " % (self._rtype, self.guid) + logger = Logger(self._rtype) + logger.debug(msg) +
+
[docs] def set_failed(self, time = None): + """ Mark ResourceManager as FAILED """ + self.set_state(ResourceState.FAILED, "_failed_time", time) + + msg = " %s guid %d ----- FAILED ----- " % (self._rtype, self.guid) + logger = Logger(self._rtype) + logger.debug(msg) +
+
[docs] def set_discovered(self, time = None): + """ Mark ResourceManager as DISCOVERED """ + self.set_state(ResourceState.DISCOVERED, "_discover_time", time) + self.debug("----- DISCOVERED ---- ") +
+
[docs] def set_reserved(self, time = None): + """ Mark ResourceManager as RESERVED """ + self.set_state(ResourceState.RESERVED, "_reserved_time", time) + self.debug("----- RESERVED ---- ") +
+
[docs] def set_provisioned(self, time = None): + """ Mark ResourceManager as PROVISIONED """ + self.set_state(ResourceState.PROVISIONED, "_provision_time", time) + self.debug("----- PROVISIONED ---- ") +
+
[docs] def set_state(self, state, state_time_attr, time = None): + """ Set the state of the RM while keeping a trace of the time """ + + # Ensure that RM state will not change after released + if self._state == ResourceState.RELEASED: + return + + time = time or tnow() + self.set_state_time(state, state_time_attr, time) +
+
[docs] def set_state_time(self, state, state_time_attr, time): + """ Set the time for the RM state change """ + setattr(self, state_time_attr, time) + self._state = state +
+
[docs]class ResourceFactory(object): + _resource_types = dict() + + @classmethod +
[docs] def resource_types(cls): + """Return the type of the Class""" + return cls._resource_types +
+ @classmethod +
[docs] def get_resource_type(cls, rtype): + """Return the type of the Class""" + return cls._resource_types.get(rtype) +
+ @classmethod +
[docs] def register_type(cls, rclass): + """Register a new Ressource Manager""" + cls._resource_types[rclass.get_rtype()] = rclass +
+ @classmethod +
[docs] def create(cls, rtype, ec, guid): + """Create a new instance of a Ressource Manager""" + rclass = cls._resource_types[rtype] + return rclass(ec, guid) +
+
[docs]def populate_factory(): + """Find and rgister all available RMs + """ + # Once the factory is populated, don't repopulate + if not ResourceFactory.resource_types(): + for rclass in find_types(): + ResourceFactory.register_type(rclass) +
+
[docs]def find_types(): + """Look into the different folders to find all the + availables Resources Managers + """ + search_path = os.environ.get("NEPI_SEARCH_PATH", "") + search_path = set(search_path.split(" ")) + + import inspect + import nepi.resources + path = os.path.dirname(nepi.resources.__file__) + search_path.add(path) + + types = set() + + for importer, modname, ispkg in pkgutil.walk_packages(search_path, + prefix = "nepi.resources."): + + loader = importer.find_module(modname) + + try: + # 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: + module = loader.load_module(modname) + + for attrname in dir(module): + if attrname.startswith("_"): + continue + + attr = getattr(module, attrname) + + if attr == ResourceManager: + continue + + if not inspect.isclass(attr): + continue + + if issubclass(attr, ResourceManager): + types.add(attr) + + if not modname in sys.modules: + sys.modules[modname] = module + + except: + import traceback + import logging + err = traceback.format_exc() + logger = logging.getLogger("Resource.find_types()") + logger.error("Error while loading Resource Managers %s" % err) + + return types +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/runner.html b/doc/sphinx/_build/html/_modules/nepi/execution/runner.html new file mode 100644 index 00000000..63b0f158 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/runner.html @@ -0,0 +1,267 @@ + + + + + + + + nepi.execution.runner — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.execution.runner

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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, ECState
+
+import math
+import numpy
+import os
+import time
+
+
[docs]class ExperimentRunner(object): + """ The ExperimentRunner entity is responsible of + re-running an experiment described by an ExperimentController + multiple time + + """ + def __init__(self): + super(ExperimentRunner, self).__init__() + +
[docs] def run(self, ec, min_runs = 1, max_runs = -1, wait_time = 0, + wait_guids = [], compute_metric_callback = None, + evaluate_convergence_callback = None ): + """ Run a same experiment independently multiple times, until the + evaluate_convergence_callback function returns True + + :param ec: Description of experiment to replicate. + The runner takes care of deploying the EC, so ec.deploy() + must not be invoked directly before or after invoking + runner.run(). + :type ec: ExperimentController + + :param min_runs: Minimum number of times the experiment must be + replicated + :type min_runs: int + + :param max_runs: Maximum number of times the experiment can be + replicated + :type max_runs: int + + :param wait_time: Time to wait in seconds on each run between invoking + ec.deploy() and ec.release(). + :type wait_time: float + + :param wait_guids: List of guids wait for finalization on each run. + This list is passed to ec.wait_finished() + :type wait_guids: list + + :param compute_metric_callback: User defined function invoked after + each experiment run to compute a metric. The metric is usually + a network measurement obtained from the data collected + during experiment execution. + The function is invoked passing the ec and the run number as arguments. + It must return the value for the computed metric(s) (usually a single + numerical value, but it can be several). + + metric = compute_metric_callback(ec, run) + + :type compute_metric_callback: function + + :param evaluate_convergence_callback: User defined function invoked after + computing the metric on each run, to evaluate the experiment was + run enough times. It takes the list of cumulated metrics produced by + the compute_metric_callback up to the current run, and decided + whether the metrics have statistically converged to a meaningful value + or not. It must return either True or False. + + stop = evaluate_convergence_callback(ec, run, metrics) + + If stop is True, then the runner will exit. + + :type evaluate_convergence_callback: function + + """ + + if (not max_runs or max_runs < 0) and not compute_metric_callback: + msg = "Undefined STOP condition, set stop_callback or max_runs" + raise RuntimeError, msg + + if compute_metric_callback and not evaluate_convergence_callback: + evaluate_convergence_callback = self.evaluate_normal_convergence + ec.logger.info(" Treating data as normal to evaluate convergence. " + "Experiment will stop when the standard error with 95% " + "confidence interval is >= 5% of the mean of the collected samples ") + + # Force persistence of experiment controller + ec._persist = True + + filepath = ec.save(dirpath = ec.exp_dir) + + samples = [] + run = 0 + stop = False + + while not stop: + run += 1 + + ec = self.run_experiment(filepath, wait_time, wait_guids) + + ec.logger.info(" RUN %d \n" % run) + + if compute_metric_callback: + metric = compute_metric_callback(ec, run) + if metric is not None: + samples.append(metric) + + if run >= min_runs and evaluate_convergence_callback: + if evaluate_convergence_callback(ec, run, samples): + stop = True + + if run >= min_runs and max_runs > -1 and run >= max_runs : + stop = True + + ec.shutdown() + del ec + + return run +
+
[docs] def evaluate_normal_convergence(self, ec, run, metrics): + """ Returns True when the confidence interval of the sample mean is + less than 5% of the mean value, for a 95% confidence level, + assuming normal distribution of the data + """ + + if len(metrics) == 0: + msg = "0 samples collected" + raise RuntimeError, msg + + x = numpy.array(metrics) + n = len(metrics) + std = x.std() + se = std / math.sqrt(n) + m = x.mean() + + # Confidence interval for 95% confidence level, + # assuming normally distributed data. + ci95 = se * 2 + + ec.logger.info(" RUN %d - SAMPLES %d MEAN %.2f STD %.2f CI (95%%) %.2f \n" % ( + run, n, m, std, ci95 ) ) + + return m * 0.05 >= ci95 +
+
[docs] def run_experiment(self, filepath, wait_time, wait_guids): + """ Run an experiment based on the description stored + in filepath. + + """ + ec = ExperimentController.load(filepath) + + ec.deploy() + + ec.wait_finished(wait_guids) + time.sleep(wait_time) + + ec.release() + + if ec.state == ECState.FAILED: + raise RuntimeError, "Experiment failed" + + return ec +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/scheduler.html b/doc/sphinx/_build/html/_modules/nepi/execution/scheduler.html new file mode 100644 index 00000000..f5ff0e15 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/scheduler.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.execution.scheduler — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.execution.scheduler

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 itertools
+import heapq
+
+
[docs]class TaskStatus: + """ Execution state of the Task + """ + NEW = 0 + DONE = 1 + ERROR = 2 +
+
[docs]class Task(object): + """ A Task represents an operation to be executed by the + ExperimentController scheduler + """ + + def __init__(self, timestamp, callback): + """ + :param timestamp: Future execution date of the operation + :type timestamp: str + + :param callback: A function to invoke in order to execute the operation + :type callback: function + + """ + self.id = None + self.timestamp = timestamp + self.callback = callback + self.result = None + self.status = TaskStatus.NEW +
+
[docs]class HeapScheduler(object): + """ Create a Heap Scheduler + + .. note:: + + This class is thread safe. + All calls to C Extensions are made atomic by the GIL in the CPython implementation. + heapq.heappush, heapq.heappop, and list access are therefore thread-safe. + + """ + + def __init__(self): + super(HeapScheduler, self).__init__() + self._queue = list() + self._valid = set() + self._idgen = itertools.count(1) + + @property +
[docs] def pending(self): + """ Returns the list of pending task ids """ + return self._valid +
+
[docs] def schedule(self, task): + """ Add a task to the queue ordered by task.timestamp and arrival order + + :param task: task to schedule + :type task: task + """ + if task.id == None: + task.id = self._idgen.next() + + entry = (task.timestamp, task.id, task) + self._valid.add(task.id) + heapq.heappush(self._queue, entry) + return task +
+
[docs] def remove(self, tid): + """ Remove a task form the queue + + :param tid: Id of the task to be removed + :type tid: int + + """ + try: + self._valid.remove(tid) + except: + pass +
+
[docs] def next(self): + """ Get the next task in the queue by timestamp and arrival order + """ + while self._queue: + try: + timestamp, tid, task = heapq.heappop(self._queue) + if tid in self._valid: + self.remove(tid) + return task + except IndexError: + # heap empty + pass + return None +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/execution/trace.html b/doc/sphinx/_build/html/_modules/nepi/execution/trace.html new file mode 100644 index 00000000..dfe0bb19 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/execution/trace.html @@ -0,0 +1,148 @@ + + + + + + + + nepi.execution.trace — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.execution.trace

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+
[docs]class TraceAttr: + """A Trace attribute defines information about a Trace that can + be queried + """ + ALL = "all" + STREAM = "stream" + PATH = "path" + SIZE = "size" +
+
[docs]class Trace(object): + """ A Trace represents information about a Resource that can + be collected + """ + + def __init__(self, name, help, enabled = False): + """ + :param name: Name of the Trace + :type name: str + + :param help: Description of the Trace + :type help: str + + :param enabled: Sets activation state of Trace + :type enabled: bool + """ + self._name = name + self._help = help + self.enabled = enabled + + @property +
[docs] def name(self): + """ Returns the name of the trace """ + return self._name +
+ @property +
[docs] def help(self): + """ Returns the help of the trace """ + return self._help +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/all/collector.html b/doc/sphinx/_build/html/_modules/nepi/resources/all/collector.html new file mode 100644 index 00000000..55ec554d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/all/collector.html @@ -0,0 +1,227 @@ + + + + + + + + nepi.resources.all.collector — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.all.collector

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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, ResourceAction
+from nepi.util.sshfuncs import ProcStatus
+
+import os
+import tempfile
+
+@clsinit_copy
+
[docs]class Collector(ResourceManager): + """ The collector entity is reponsible of collecting traces + of a same type associated to RMs into a local directory. + + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + _rtype = "Collector" + _help = "A Collector can be attached to a trace name on another " \ + "ResourceManager and will retrieve and store the trace content " \ + "in a local file at the end of the experiment" + _platform = "all" + + @classmethod + def _register_attributes(cls): + trace_name = Attribute("traceName", + "Name of the trace to be collected", + flags = Flags.Design) + + sub_dir = Attribute("subDir", + "Sub directory to collect traces into", + flags = Flags.Design) + + rename = Attribute("rename", + "Name to give to the collected trace file", + flags = Flags.Design) + + cls._register_attribute(trace_name) + cls._register_attribute(sub_dir) + cls._register_attribute(rename) + + def __init__(self, ec, guid): + super(Collector, self).__init__(ec, guid) + self._store_path = None + + @property +
[docs] def store_path(self): + return self._store_path +
+
[docs] def do_provision(self): + trace_name = self.get("traceName") + if not trace_name: + self.fail() + + msg = "No traceName was specified" + self.error(msg) + raise RuntimeError, msg + + self._store_path = self.ec.run_dir + + subdir = self.get("subDir") + if subdir: + self._store_path = os.path.join(self.store_path, subdir) + + msg = "Creating local directory at %s to store %s traces " % ( + self.store_path, trace_name) + self.info(msg) + + try: + os.makedirs(self.store_path) + except OSError: + pass + + super(Collector, self).do_provision() +
+
[docs] def do_deploy(self): + self.do_discover() + self.do_provision() + + super(Collector, self).do_deploy() +
+
[docs] def do_release(self): + trace_name = self.get("traceName") + rename = self.get("rename") or trace_name + + msg = "Collecting '%s' traces to local directory %s" % ( + trace_name, self.store_path) + self.info(msg) + + rms = self.get_connected() + for rm in rms: + fpath = os.path.join(self.store_path, "%d.%s" % (rm.guid, + rename)) + + try: + result = self.ec.trace(rm.guid, trace_name) + f = open(fpath, "w") + f.write(result) + f.close() + except: + import traceback + err = traceback.format_exc() + msg = "Couldn't retrieve trace %s for %d at %s " % (trace_name, + rm.guid, fpath) + self.error(msg, out = "", err = err) + continue + + super(Collector, self).do_release() +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/application.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/application.html new file mode 100644 index 00000000..37493562 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/application.html @@ -0,0 +1,860 @@ + + + + + + + + nepi.resources.linux.application — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.application

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.node import LinuxNode
+from nepi.util.sshfuncs import ProcStatus
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+import subprocess
+
+# TODO: Resolve wildcards in commands!!
+# TODO: When a failure occurs during deployment, scp and ssh processes are left running behind!!
+
+@clsinit_copy
+
[docs]class LinuxApplication(ResourceManager): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + .. note:: + + A LinuxApplication RM represents a process that can be executed in + a remote Linux host using SSH. + + The LinuxApplication RM takes care of uploadin sources and any files + needed to run the experiment, to the remote host. + It also allows to provide source compilation (build) and installation + instructions, and takes care of automating the sources build and + installation tasks for the user. + + It is important to note that files uploaded to the remote host have + two possible scopes: single-experiment or multi-experiment. + Single experiment files are those that will not be re-used by other + experiments. Multi-experiment files are those that will. + Sources and shared files are always made available to all experiments. + + Directory structure: + + The directory structure used by LinuxApplication RM at the Linux + host is the following: + + ${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/nepi-exp --> Base directory for single-experiment files + | + ${EXP_HOME} |- /<exp-id> --> Base directory for experiment exp-id + | + ${APP_HOME} |- /<app-guid> --> Base directory for application + | specific files (e.g. command.sh, input) + | + ${RUN_HOME} |- /<run-id> --> Base directory for run specific + + """ + + _rtype = "linux::Application" + _help = "Runs an application on a Linux host with a BASH command " + _platform = "linux" + + @classmethod + def _register_attributes(cls): + 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.Design) + forward_x11 = Attribute("forwardX11", "Enables X11 forwarding for SSH connections", + flags = Flags.Design) + env = Attribute("env", "Environment variables string for command execution", + flags = Flags.Design) + sudo = Attribute("sudo", "Run with root privileges", + flags = Flags.Design) + depends = Attribute("depends", + "Space-separated list of packages required to run the application", + flags = Flags.Design) + sources = Attribute("sources", + "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.Design) + files = Attribute("files", + "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.Design) + libs = Attribute("libs", + "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.Design) + bins = Attribute("bins", + "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.Design) + code = Attribute("code", + "Plain text source code to be uploaded to the ${APP_HOME} directory. ", + flags = Flags.Design) + build = Attribute("build", + "Build commands to execute after deploying the sources. " + "Sources are uploaded to the ${SRC} directory and code " + "is uploaded to the ${APP_HOME} directory. \n" + "Usage example: tar xzf ${SRC}/my-app.tgz && cd my-app && " + "./configure && make && make clean.\n" + "Make sure to make the build commands return with a nonzero exit " + "code on error.", + flags = Flags.Design) + install = Attribute("install", + "Commands to transfer built files to their final destinations. " + "Install commands are executed after build commands. ", + flags = Flags.Design) + stdin = Attribute("stdin", "Standard input for the 'command'", + flags = Flags.Design) + tear_down = Attribute("tearDown", "Command to be executed just before " + "releasing the resource", + flags = Flags.Design) + + cls._register_attribute(command) + cls._register_attribute(forward_x11) + cls._register_attribute(env) + cls._register_attribute(sudo) + cls._register_attribute(depends) + cls._register_attribute(sources) + cls._register_attribute(code) + cls._register_attribute(files) + cls._register_attribute(bins) + cls._register_attribute(libs) + cls._register_attribute(build) + cls._register_attribute(install) + cls._register_attribute(stdin) + cls._register_attribute(tear_down) + + @classmethod + def _register_traces(cls): + stdout = Trace("stdout", "Standard output stream", enabled = True) + stderr = Trace("stderr", "Standard error stream", enabled = True) + + cls._register_trace(stdout) + cls._register_trace(stderr) + + def __init__(self, ec, guid): + super(LinuxApplication, self).__init__(ec, guid) + self._pid = None + self._ppid = None + self._node = None + self._home = "app-%s" % self.guid + + # whether the command should run in foreground attached + # to a terminal + self._in_foreground = False + + # whether to use sudo to kill the application process + self._sudo_kill = False + + # keep a reference to the running process handler when + # the command is not executed as remote daemon in background + self._proc = None + + # timestamp of last state check of the application + self._last_state_check = tnow() + +
[docs] def log_message(self, msg): + return " guid %d - host %s - %s " % (self.guid, + self.node.get("hostname"), msg) +
+ @property +
[docs] def node(self): + if not self._node: + node = self.get_connected(LinuxNode.get_rtype()) + if not node: + msg = "Application %s guid %d NOT connected to Node" % ( + self._rtype, self.guid) + raise RuntimeError, msg + + self._node = node[0] + + return self._node +
+ @property +
[docs] def app_home(self): + return os.path.join(self.node.exp_home, self._home) +
+ @property +
[docs] def run_home(self): + return os.path.join(self.app_home, self.ec.run_id) +
+ @property +
[docs] def pid(self): + return self._pid +
+ @property +
[docs] def ppid(self): + return self._ppid +
+ @property +
[docs] def in_foreground(self): + """ Returns True if the command needs to be executed in foreground. + This means that command will be executed using 'execute' instead of + 'run' ('run' executes a command in background and detached from the + terminal) + + When using X11 forwarding option, the command can not run in background + and detached from a terminal, since we need to keep the terminal attached + to interact with it. + """ + return self.get("forwardX11") or self._in_foreground +
+
[docs] def trace_filepath(self, filename): + return os.path.join(self.run_home, filename) +
+
[docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + self.info("Retrieving '%s' trace %s " % (name, attr)) + + path = self.trace_filepath(name) + + command = "(test -f %s && echo 'success') || echo 'error'" % path + (out, err), proc = self.node.execute(command) + + if (err and proc.poll()) or out.find("error") != -1: + msg = " Couldn't find trace %s " % name + self.error(msg, out, err) + return None + + if attr == TraceAttr.PATH: + return path + + if attr == TraceAttr.ALL: + (out, err), proc = self.node.check_output(self.run_home, name) + + if proc.poll(): + msg = " Couldn't read trace %s " % name + self.error(msg, out, err) + return None + + return out + + if attr == TraceAttr.STREAM: + cmd = "dd if=%s bs=%d count=1 skip=%d" % (path, block, offset) + elif attr == TraceAttr.SIZE: + cmd = "stat -c%%s %s " % path + + (out, err), proc = self.node.execute(cmd) + + if proc.poll(): + msg = " Couldn't find trace %s " % name + self.error(msg, out, err) + return None + + if attr == TraceAttr.SIZE: + out = int(out.strip()) + + return out +
+
[docs] def do_provision(self): + # take a snapshot of the system if user is root + # to ensure that cleanProcess will not kill + # pre-existent processes + if self.node.get("username") == 'root': + import pickle + procs = dict() + ps_aux = "ps aux |awk '{print $2,$11}'" + (out, err), proc = self.node.execute(ps_aux) + if len(out) != 0: + for line in out.strip().split("\n"): + parts = line.strip().split(" ") + procs[parts[0]] = parts[1] + pickle.dump(procs, open("/tmp/save.proc", "wb")) + + # create run dir for application + self.node.mkdir(self.run_home) + + # List of all the provision methods to invoke + steps = [ + # upload sources + self.upload_sources, + # upload files + self.upload_files, + # upload binaries + self.upload_binaries, + # upload libraries + self.upload_libraries, + # upload code + self.upload_code, + # upload stdin + self.upload_stdin, + # install dependencies + self.install_dependencies, + # build + self.build, + # Install + self.install] + + command = [] + + # Since provisioning takes a long time, before + # each step we check that the EC is still + for step in steps: + if self.ec.abort: + self.debug("Interrupting provisioning. EC says 'ABORT") + return + + ret = step() + if ret: + command.append(ret) + + # upload deploy script + deploy_command = ";".join(command) + self.execute_deploy_command(deploy_command) + + # upload start script + self.upload_start_command() + + self.info("Provisioning finished") + + super(LinuxApplication, self).do_provision() +
+
[docs] def upload_start_command(self, overwrite = False): + # Upload command to remote bash script + # - only if command can be executed in background and detached + command = self.get("command") + + if command and not self.in_foreground: + self.info("Uploading command '%s'" % command) + + # replace application specific paths in the command + command = self.replace_paths(command) + # replace application specific paths in the environment + env = self.get("env") + env = env and self.replace_paths(env) + + shfile = os.path.join(self.app_home, "start.sh") + + self.node.upload_command(command, + shfile = shfile, + env = env, + overwrite = overwrite) +
+
[docs] def execute_deploy_command(self, command, prefix="deploy"): + if command: + # replace application specific paths in the command + command = self.replace_paths(command) + + # replace application specific paths in the environment + env = self.get("env") + env = env and self.replace_paths(env) + + # 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, "%s.sh" % prefix) + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = False, + pidfile = "%s_pidfile" % prefix, + ecodefile = "%s_exitcode" % prefix, + stdout = "%s_stdout" % prefix, + stderr = "%s_stderr" % prefix) +
+
[docs] 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 = map(str.strip, sources.split(";")) + + # Separate sources that should be downloaded from + # the web, from sources that should be uploaded from + # the local machine + command = [] + for source in list(sources): + if source.startswith("http") or source.startswith("https"): + # remove the hhtp source from the sources list + sources.remove(source) + + command.append( " ( " + # Check if the source already exists + " 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_dir)s %(source)s && " + " ls %(src_dir)s/%(basename)s " + " ) ) " % { + "basename": os.path.basename(source), + "source": source, + "src_dir": src_dir + }) + + command = " && ".join(command) + + # replace application specific paths in the command + command = self.replace_paths(command) + + if sources: + sources = ';'.join(sources) + self.node.upload(sources, src_dir, overwrite = False) + + return command +
+
[docs] 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) +
+
[docs] 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) +
+
[docs] 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) +
+
[docs] def upload_code(self, code = None): + if not code: + code = self.get("code") + + if code: + self.info("Uploading code") + + dst = os.path.join(self.app_home, "code") + self.node.upload(code, dst, overwrite = False, text = True) +
+
[docs] 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 + 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 + command = "( cd %(app_home)s ; [ ! -f stdin ] && ln -s %(stdin)s stdin )" % ({ + "app_home": self.app_home, + "stdin": dst }) + + return command +
+
[docs] 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) +
+
[docs] def build(self, build = None): + if not build: + build = self.get("build") + + if build: + self.info("Building sources ") + + # replace application specific paths in the command + return self.replace_paths(build) +
+
[docs] def install(self, install = None): + if not install: + install = self.get("install") + + if install: + self.info("Installing sources ") + + # replace application specific paths in the command + return self.replace_paths(install) +
+
[docs] def do_deploy(self): + # Wait until node is associated and deployed + node = self.node + if not node or node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") or "" + self.info("Deploying command '%s' " % command) + self.do_discover() + self.do_provision() + + super(LinuxApplication, self).do_deploy() +
+
[docs] def do_start(self): + command = self.get("command") + + self.info("Starting command '%s'" % command) + + if not command: + # If no command was given (i.e. Application was used for dependency + # installation), then the application is directly marked as STOPPED + super(LinuxApplication, self).set_stopped() + else: + if self.in_foreground: + self._run_in_foreground() + else: + self._run_in_background() + + super(LinuxApplication, self).do_start() +
+ def _run_in_foreground(self): + command = self.get("command") + sudo = self.get("sudo") or False + x11 = self.get("forwardX11") + env = self.get("env") + + # Command will be launched in foreground and attached to the + # terminal using the node 'execute' in non blocking mode. + + # We save the reference to the process in self._proc + # to be able to kill the process from the stop method. + # We also set blocking = False, since we don't want the + # thread to block until the execution finishes. + (out, err), self._proc = self.execute_command(command, + env = env, + sudo = sudo, + forward_x11 = x11, + blocking = False) + + if self._proc.poll(): + self.error(msg, out, err) + raise RuntimeError, msg + + def _run_in_background(self): + command = self.get("command") + env = self.get("env") + sudo = self.get("sudo") or False + + stdout = "stdout" + stderr = "stderr" + stdin = os.path.join(self.app_home, "stdin") if self.get("stdin") \ + else None + + # Command will be run as a daemon in baground and detached from any + # terminal. + # The command to run was previously uploaded to a bash script + # during deployment, now we launch the remote script using 'run' + # method from the node. + cmd = "bash %s" % os.path.join(self.app_home, "start.sh") + (out, err), proc = self.node.run(cmd, self.run_home, + stdin = stdin, + stdout = stdout, + stderr = stderr, + sudo = sudo) + + # check if execution errors occurred + msg = " Failed to start command '%s' " % command + + if proc.poll(): + self.error(msg, out, err) + raise RuntimeError, msg + + # Wait for pid file to be generated + pid, ppid = self.node.wait_pid(self.run_home) + if pid: self._pid = int(pid) + if ppid: self._ppid = int(ppid) + + # If the process is not running, check for error information + # on the remote machine + if not self.pid or not self.ppid: + (out, err), proc = self.node.check_errors(self.run_home, + stderr = stderr) + + # Out is what was written in the stderr file + if err: + msg = " Failed to start command '%s' " % command + self.error(msg, out, err) + raise RuntimeError, msg + +
[docs] def do_stop(self): + """ Stops application execution + """ + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + + self.info("Stopping command '%s' " % command) + + # If the command is running in foreground (it was launched using + # the node 'execute' method), then we use the handler to the Popen + # process to kill it. Else we send a kill signal using the pid and ppid + # retrieved after running the command with the node 'run' method + if self._proc: + self._proc.kill() + else: + # Only try to kill the process if the pid and ppid + # were retrieved + if self.pid and self.ppid: + (out, err), proc = self.node.kill(self.pid, self.ppid, + sudo = self._sudo_kill) + + """ + # TODO: check if execution errors occurred + if (proc and proc.poll()) or err: + msg = " Failed to STOP command '%s' " % self.get("command") + self.error(msg, out, err) + """ + + super(LinuxApplication, self).do_stop() +
+
[docs] def do_release(self): + self.info("Releasing resource") + + self.do_stop() + + tear_down = self.get("tearDown") + if tear_down: + self.node.execute(tear_down) + + hard_release = self.get("hardRelease") + if hard_release: + self.node.rmdir(self.app_home) + + super(LinuxApplication, self).do_release() +
+ @property +
[docs] def state(self): + """ Returns the state of the application + """ + if self._state == ResourceState.STARTED: + if self.in_foreground: + # Check if the process we used to execute the command + # is still running ... + retcode = self._proc.poll() + + # retcode == None -> running + # retcode > 0 -> error + # retcode == 0 -> finished + if retcode: + out = "" + msg = " Failed to execute command '%s'" % self.get("command") + err = self._proc.stderr.read() + self.error(msg, out, err) + self.do_fail() + + elif retcode == 0: + self.set_stopped() + else: + # We need to query the status of the command we launched in + # background. In order to avoid overwhelming the remote host and + # the local processor with too many ssh queries, the state is only + # requested every 'state_check_delay' seconds. + state_check_delay = 0.5 + if tdiffsec(tnow(), self._last_state_check) > state_check_delay: + if self.pid and self.ppid: + # Make sure the process is still running in background + status = self.node.status(self.pid, self.ppid) + + if status == ProcStatus.FINISHED: + # If the program finished, check if execution + # errors occurred + (out, err), proc = self.node.check_errors( + self.run_home) + + if err: + msg = "Failed to execute command '%s'" % \ + self.get("command") + self.error(msg, out, err) + self.do_fail() + else: + self.set_stopped() + + self._last_state_check = tnow() + + return self._state +
+
[docs] def execute_command(self, command, + env=None, + sudo=False, + tty=False, + forward_x11=False, + blocking=False): + + environ = "" + if env: + environ = self.node.format_environment(env, inline=True) + command = environ + command + command = self.replace_paths(command) + + return self.node.execute(command, + sudo=sudo, + tty=tty, + forward_x11=forward_x11, + blocking=blocking) +
+
[docs] def replace_paths(self, command, node=None, app_home=None, run_home=None): + """ + Replace all special path tags with shell-escaped actual paths. + """ + if not node: + node=self.node + + if not app_home: + app_home=self.app_home + + if not run_home: + run_home = self.run_home + + return ( command + .replace("${USR}", node.usr_dir) + .replace("${LIB}", node.lib_dir) + .replace("${BIN}", node.bin_dir) + .replace("${SRC}", node.src_dir) + .replace("${SHARE}", node.share_dir) + .replace("${EXP}", node.exp_dir) + .replace("${EXP_HOME}", node.exp_home) + .replace("${APP_HOME}", app_home) + .replace("${RUN_HOME}", run_home) + .replace("${NODE_HOME}", node.node_home) + .replace("${HOME}", node.home_dir) + ) +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnapplication.html new file mode 100644 index 00000000..b46dd26e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnapplication.html @@ -0,0 +1,159 @@ + + + + + + + + nepi.resources.linux.ccn.ccnapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.ccnapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.application import LinuxApplication
+from nepi.resources.linux.ccn.ccnd import LinuxCCND
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxCCNApplication(LinuxApplication): + _rtype = "linux::CCNApplication" + + def __init__(self, ec, guid): + super(LinuxCCNApplication, self).__init__(ec, guid) + self._home = "ccnapp-%s" % self.guid + + @property +
[docs] def ccnd(self): + ccnd = self.get_connected(LinuxCCND.get_rtype()) + if ccnd: return ccnd[0] + return None +
+ @property +
[docs] def node(self): + if self.ccnd: return self.ccnd.node + return None +
+
[docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") or "" + + self.info("Deploying command '%s' " % command) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + self.set_ready() +
+ @property + def _environment(self): + return self.ccnd.path + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncat.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncat.html new file mode 100644 index 00000000..f2bbea97 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncat.html @@ -0,0 +1,163 @@ + + + + + + + + nepi.resources.linux.ccn.ccncat — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.ccncat

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ccn.ccnapplication import LinuxCCNApplication
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxCCNCat(LinuxCCNApplication): + _rtype = "linux::CCNCat" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the content to peek", + flags = Flags.Design) + + pipeline = Attribute("pipeline", + "CCNCat pipeline", + flags = Flags.Design) + + cls._register_attribute(content_name) + cls._register_attribute(pipeline) + + def __init__(self, ec, guid): + super(LinuxCCNCat, self).__init__(ec, guid) + self._home = "ccncat-%s" % self.guid + +
[docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") + if not command: + command = "ccncat %s" % self.get("contentName") + if self.get("pipeline"): + command += " -p %s " % self.get("pipeline") + + self.set("command", command) + + self.info("Deploying command '%s' " % command) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncontent.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncontent.html new file mode 100644 index 00000000..9d0f2479 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccncontent.html @@ -0,0 +1,241 @@ + + + + + + + + nepi.resources.linux.ccn.ccncontent — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.ccncontent

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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, \
+    ResourceAction
+from nepi.resources.linux.application import LinuxApplication
+from nepi.resources.linux.ccn.ccnr import LinuxCCNR
+from nepi.util.timefuncs import tnow
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxCCNContent(LinuxApplication): + _rtype = "linux::CCNContent" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "The name of the content to publish (e.g. ccn:/VIDEO) ", + flags = Flags.Design) + + content = Attribute("content", + "The content to publish. It can be a path to a file or plain text ", + flags = Flags.Design) + + scope = Attribute("scope", + "Use the given scope on the start-write request (if -r specified). " + "scope can be 1 (local), 2 (neighborhood), or 3 (unlimited). " + "Note that a scope of 3 is encoded as the absence of any scope in the interest. ", + type = Types.Integer, + default = 1, + flags = Flags.Design) + + cls._register_attribute(content_name) + cls._register_attribute(content) + cls._register_attribute(scope) + + def __init__(self, ec, guid): + super(LinuxCCNContent, self).__init__(ec, guid) + self._home = "content-%s" % self.guid + + @property +
[docs] def ccnr(self): + ccnr = self.get_connected(LinuxCCNR.get_rtype()) + if ccnr: return ccnr[0] + return None +
+ @property +
[docs] def ccnd(self): + if self.ccnr: return self.ccnr.ccnd + return None +
+ @property +
[docs] def node(self): + if self.ccnr: return self.ccnr.node + return None +
+
[docs] def do_deploy(self): + if not self.ccnr or self.ccnr.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + + # ccnr needs to wait until ccnd is deployed and running + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", self._environment) + + # set content to stdin, so the content will be + # uploaded during provision + self.set("stdin", self.get("content")) + + command = self.get("command") + + self.info("Deploying command '%s' " % command) + + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + self.info("Uploading command '%s'" % command) + + # We want to make sure the content is published + # before the experiment starts. + # Run the command as a bash script in the background, + # in the host ( but wait until the command has + # finished to continue ) + env = self.replace_paths(env) + command = self.replace_paths(command) + + (out, err), proc = self.execute_command(command, + env, blocking = True) + + if proc.poll(): + msg = "Failed to execute command" + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+ @property + def _start_command(self): + command = ["ccnseqwriter"] + command.append("-r %s" % self.get("contentName")) + command.append("-s %d" % self.get("scope")) + command.append("< %s" % os.path.join(self.app_home, 'stdin')) + + command = " ".join(command) + return command + + @property + def _environment(self): + return self.ccnd.path + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnd.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnd.html new file mode 100644 index 00000000..062828ab --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnd.html @@ -0,0 +1,442 @@ + + + + + + + + nepi.resources.linux.ccn.ccnd — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.ccnd

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.application import LinuxApplication
+from nepi.resources.linux.node import OSType
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+
+# TODO: use ccndlogging to dynamically change the logging level
+
+
+@clsinit_copy
+
[docs]class LinuxCCND(LinuxApplication): + _rtype = "linux::CCND" + + @classmethod + def _register_attributes(cls): + debug = Attribute("debug", "Sets the CCND_DEBUG environmental variable. " + " Allowed values are : \n" + " 0 - no messages \n" + " 1 - basic messages (any non-zero value gets these) \n" + " 2 - interest messages \n" + " 4 - content messages \n" + " 8 - matching details \n" + " 16 - interest details \n" + " 32 - gory interest details \n" + " 64 - log occasional human-readable timestamps \n" + " 128 - face registration debugging \n" + " -1 - max logging \n" + " Or apply bitwise OR to these values to get combinations of them", + type = Types.Integer, + flags = Flags.Design) + + port = Attribute("port", "Sets the CCN_LOCAL_PORT environmental variable. " + "Defaults to 9695 ", + flags = Flags.Design) + + sockname = Attribute("sockname", + "Sets the CCN_LOCAL_SCOKNAME environmental variable. " + "Defaults to /tmp/.ccnd.sock", + flags = Flags.Design) + + capacity = Attribute("capacity", + "Sets the CCND_CAP environmental variable. " + "Capacity limit in terms of ContentObjects", + flags = Flags.Design) + + mtu = Attribute("mtu", "Sets the CCND_MTU environmental variable. ", + flags = Flags.Design) + + data_pause = Attribute("dataPauseMicrosec", + "Sets the CCND_DATA_PAUSE_MICROSEC environmental variable. ", + flags = Flags.Design) + + default_stale = Attribute("defaultTimeToStale", + "Sets the CCND_DEFAULT_TIME_TO_STALE environmental variable. ", + flags = Flags.Design) + + max_stale = Attribute("maxTimeToStale", + "Sets the CCND_MAX_TIME_TO_STALE environmental variable. ", + flags = Flags.Design) + + max_rte = Attribute("maxRteMicrosec", + "Sets the CCND_MAX_RTE_MICROSEC environmental variable. ", + flags = Flags.Design) + + keystore = Attribute("keyStoreDirectory", + "Sets the CCND_KEYSTORE_DIRECTORY environmental variable. ", + flags = Flags.Design) + + listen_on = Attribute("listenOn", + "Sets the CCND_LISTEN_ON environmental variable. ", + flags = Flags.Design) + + autoreg = Attribute("autoreg", + "Sets the CCND_AUTOREG environmental variable. ", + flags = Flags.Design) + + prefix = Attribute("prefix", + "Sets the CCND_PREFIX environmental variable. ", + flags = Flags.Design) + + cls._register_attribute(debug) + cls._register_attribute(port) + cls._register_attribute(sockname) + cls._register_attribute(capacity) + cls._register_attribute(mtu) + cls._register_attribute(data_pause) + cls._register_attribute(default_stale) + cls._register_attribute(max_stale) + cls._register_attribute(max_rte) + cls._register_attribute(keystore) + cls._register_attribute(listen_on) + cls._register_attribute(autoreg) + cls._register_attribute(prefix) + + @classmethod + def _register_traces(cls): + log = Trace("log", "CCND log output") + status = Trace("status", "ccndstatus output") + + cls._register_trace(log) + cls._register_trace(status) + + def __init__(self, ec, guid): + super(LinuxCCND, self).__init__(ec, guid) + self._home = "ccnd-%s" % self.guid + self._version = "ccnx" + + @property +
[docs] def version(self): + return self._version +
+ @property +
[docs] def path(self): + return "PATH=$PATH:${BIN}/%s/" % self.version +
+
[docs] 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(self.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 not self.get("sources"): + self.set("sources", self._sources) + + sources = self.get("sources") + source = sources.split(" ")[0] + basename = os.path.basename(source) + self._version = ( basename.strip().replace(".tar.gz", "") + .replace(".tar","") + .replace(".gz","") + .replace(".zip","") ) + + 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) + + command = self.get("command") + + self.info("Deploying command '%s' " % command) + + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] 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.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = False, + env = env) +
+
[docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_stop(self): + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % command) + + command = "ccndstop" + env = self.get("env") + + # replace application specific paths in the command + command = self.replace_paths(command) + env = env and self.replace_paths(env) + + # Upload the command to a file, and execute asynchronously + shfile = os.path.join(self.app_home, "stop.sh") + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = False, + env = env, + pidfile = "ccndstop_pidfile", + ecodefile = "ccndstop_exitcode", + stdout = "ccndstop_stdout", + stderr = "ccndstop_stderr") + + self.set_stopped() +
+ @property +
[docs] def state(self): + # First check if the ccnd has failed + state_check_delay = 0.5 + if self._state == ResourceState.STARTED and \ + tdiffsec(tnow(), self._last_state_check) > state_check_delay: + (out, err), proc = self._ccndstatus() + + retcode = proc.poll() + + if retcode == 1 and err.find("No such file or directory") > -1: + # ccnd is not running (socket not found) + self.set_stopped() + elif retcode: + # other errors ... + msg = " Failed to execute command '%s'" % self.get("command") + self.error(msg, out, err) + self.fail() + + self._last_state_check = tnow() + + return self._state +
+ def _ccndstatus(self): + env = self.get('env') or "" + environ = self.node.format_environment(env, inline = True) + command = environ + " ccndstatus" + command = self.replace_paths(command) + + return self.node.execute(command) + + @property + def _start_command(self): + return "ccndstart" + + @property + def _dependencies(self): + if self.node.use_rpm: + return ( " autoconf openssl-devel expat-devel libpcap-devel " + " ecryptfs-utils-devel libxml2-devel automake gawk " + " gcc gcc-c++ git pcre-devel make ") + elif self.node.use_deb: + return ( " autoconf libssl-dev libexpat-dev libpcap-dev " + " libecryptfs0 libxml2-utils automake gawk gcc g++ " + " git-core pkg-config libpcre3-dev make ") + return "" + + @property + def _sources(self): + return "http://www.ccnx.org/releases/ccnx-0.8.2.tar.gz" + + @property + def _build(self): + sources = self.get("sources").split(" ")[0] + sources = os.path.basename(sources) + + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/%(version)s/ccnd && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, untar and build + " ( " + " mkdir -p ${SRC}/%(version)s && " + " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/%(version)s " + " ) && " + "cd ${SRC}/%(version)s && " + # Just execute and silence warnings... + " ( ./configure && make ) " + " )") % ({ 'sources': sources, + 'version': self.version + }) + + @property + def _install(self): + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/%(version)s/ccnd && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, install + " mkdir -p ${BIN}/%(version)s && " + " mv ${SRC}/%(version)s/bin/* ${BIN}/%(version)s/ " + " )" + ) % ({ 'version': self.version + }) + + @property + def _environment(self): + envs = dict({ + "debug": "CCND_DEBUG", + "port": "CCN_LOCAL_PORT", + "sockname" : "CCN_LOCAL_SOCKNAME", + "capacity" : "CCND_CAP", + "mtu" : "CCND_MTU", + "dataPauseMicrosec" : "CCND_DATA_PAUSE_MICROSEC", + "defaultTimeToStale" : "CCND_DEFAULT_TIME_TO_STALE", + "maxTimeToStale" : "CCND_MAX_TIME_TO_STALE", + "maxRteMicrosec" : "CCND_MAX_RTE_MICROSEC", + "keyStoreDirectory" : "CCND_KEYSTORE_DIRECTORY", + "listenOn" : "CCND_LISTEN_ON", + "autoreg" : "CCND_AUTOREG", + "prefix" : "CCND_PREFIX", + }) + + env = self.path + env += " ".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))) \ + if self.get(k) else "", envs.keys())) + + return env + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpeek.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpeek.html new file mode 100644 index 00000000..8d52c8fc --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpeek.html @@ -0,0 +1,155 @@ + + + + + + + + nepi.resources.linux.ccn.ccnpeek — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.ccnpeek

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ccn.ccnapplication import LinuxCCNApplication
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxCCNPeek(LinuxCCNApplication): + _rtype = "linux::CCNPeek" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the content to peek", + flags = Flags.Design) + + cls._register_attribute(content_name) + + def __init__(self, ec, guid): + super(LinuxCCNPeek, self).__init__(ec, guid) + self._home = "ccnpeek-%s" % self.guid + +
[docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") + if not command: + command = "ccnpeek %s" % self.get("contentName") + self.set("command", command) + + self.info("Deploying command '%s' " % command) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnping.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnping.html new file mode 100644 index 00000000..fcac0904 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnping.html @@ -0,0 +1,186 @@ + + + + + + + + nepi.resources.linux.ccn.ccnping — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.ccnping

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.resources.linux.ccn.ccnpingserver import LinuxCCNPingServer
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxCCNPing(LinuxCCNPingServer): + _rtype = "linux::CCNPing" + + @classmethod + def _register_attributes(cls): + interval = Attribute("i", + "Set ping interval in seconds (minimum 0.10 second) ", + type = Types.Integer, + flags = Flags.Design) + + count = Attribute("c", + "Total number of pings", + type = Types.Double, + flags = Flags.Design) + + number = Attribute("n", + "Set the starting number, the number is incremented by 1 after each Interest ", + type = Types.Integer, + flags = Flags.Design) + + prefix = Attribute("prefix", + "Prefix to serve content (e.g. ccnx:/name/prefix)", + flags = Flags.Design) + + cls._register_attribute(interval) + cls._register_attribute(count) + cls._register_attribute(number) + cls._register_attribute(prefix) + + def __init__(self, ec, guid): + super(LinuxCCNPing, self).__init__(ec, guid) + self._home = "ccnping-%s" % self.guid + + @property +
[docs] def ccnpingserver(self): + ccnpingserver = self.get_connected(LinuxCCNPingServer.get_rtype()) + if ccnpingserver: return ccnpingserver[0] + return None +
+
[docs] def do_start(self): + if not self.ccnpingserver or \ + self.ccnpingserver.state < ResourceState.STARTED: + self.debug("---- RESCHEDULING START---- ccnpingserver state %s " % \ + self.ccnpingserver.state ) + self.ec.schedule(self.reschedule_delay, self.start) + else: + super(LinuxCCNPing, self).do_start() +
+ @property + def _start_command(self): + args = [] + args.append("ccnping") + args.append(self.get("prefix")) + if self.get("c"): + args.append("-c %d" % self.get("c")) + if self.get("n"): + args.append("-n %d" % self.get("n")) + if self.get("i"): + args.append("-i %.2f" % self.get("i")) + + command = " ".join(args) + + return command + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpingserver.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpingserver.html new file mode 100644 index 00000000..d3b8af68 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpingserver.html @@ -0,0 +1,225 @@ + + + + + + + + nepi.resources.linux.ccn.ccnpingserver — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.ccnpingserver

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.resources.linux.ccn.ccnapplication import LinuxCCNApplication
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxCCNPingServer(LinuxCCNApplication): + _rtype = "linux::CCNPingServer" + + @classmethod + def _register_attributes(cls): + daemon = Attribute("d", + "Run ccnping server as a daemon in background", + type = Types.Bool, + default = False, + flags = Flags.Design) + + freshness = Attribute("x", + "Set FreshnessSeconds", + type = Types.Integer, + flags = Flags.Design) + + prefix = Attribute("prefix", + "Prefix to serve content (e.g. ccnx:/name/prefix)", + flags = Flags.Design) + + cls._register_attribute(daemon) + cls._register_attribute(freshness) + cls._register_attribute(prefix) + + def __init__(self, ec, guid): + super(LinuxCCNPingServer, self).__init__(ec, guid) + self._home = "ccnping-serv-%s" % self.guid + +
[docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", self._environment) + + if not self.get("depends"): + self.set("depends", self._dependencies) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("install"): + self.set("install", self._install) + + super(LinuxCCNPingServer, self).do_deploy() +
+ @property + def _start_command(self): + args = [] + args.append("ccnpingserver") + args.append(self.get("prefix")) + if self.get("d") == True: + args.append("-d") + if self.get("x"): + args.append("-x %d" % self.get("x")) + + command = " ".join(args) + + return command + + @property + def _dependencies(self): + return "git" + + @property + def _build(self): + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/ccnping && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, untar and build + " ( " + " git clone git://github.com/NDN-Routing/ccnping ${SRC}/ccnping " + " ) && " + # build + "cd ${SRC}/ccnping && " + " ( " + " ./configure LDFLAGS=-L${SRC}/ccnx-0.7.2/lib CFLAGS=-I${SRC}/ccnx-0.7.2/include " + " --prefix=${BIN}/ccnping && make " + " ) " + " )") + + @property + def _install(self): + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/ccnping && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, install + " mkdir -p ${BIN}/ccnping && " + " mv ${SRC}/ccnping/ccnping ${BIN}/ccnping/ && " + " mv ${SRC}/ccnping/ccnpingserver ${BIN}/ccnping/ " + " )" + ) + + @property + def _environment(self): + return "%s:%s" % (self.ccnd.path, "${BIN}/ccnping") + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpoke.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpoke.html new file mode 100644 index 00000000..71ff3d7b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnpoke.html @@ -0,0 +1,163 @@ + + + + + + + + nepi.resources.linux.ccn.ccnpoke — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.ccnpoke

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ccn.ccnapplication import LinuxCCNApplication
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxCCNPoke(LinuxCCNApplication): + _rtype = "linux::CCNPoke" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the content to peek", + flags = Flags.Design) + + content = Attribute("content", + "Content to poke (as a text string)", + flags = Flags.Design) + + cls._register_attribute(content_name) + cls._register_attribute(content) + + def __init__(self, ec, guid): + super(LinuxCCNPoke, self).__init__(ec, guid) + self._home = "ccnpoke-%s" % self.guid + +
[docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + command = self.get("command") + if not command: + command = "ccnpoke %s" % self.get("contentName") + self.set("command", command) + + self.info("Deploying command '%s' " % command) + + if self.get("content"): + self.set("stdin", self.get("content")) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnr.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnr.html new file mode 100644 index 00000000..382fc972 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/ccnr.html @@ -0,0 +1,397 @@ + + + + + + + + nepi.resources.linux.ccn.ccnr — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.ccnr

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 clsinit_copy, ResourceState, \
+    ResourceAction
+from nepi.resources.linux.application import LinuxApplication
+from nepi.resources.linux.ccn.ccnd import LinuxCCND
+from nepi.util.timefuncs import tnow
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxCCNR(LinuxApplication): + _rtype = "linux::CCNR" + + @classmethod + def _register_attributes(cls): + max_fanout = Attribute("maxFanout", + "Sets the CCNR_BTREE_MAX_FANOUT environmental variable. ", + flags = Flags.Design) + + max_leaf_entries = Attribute("maxLeafEntries", + "Sets the CCNR_BTREE_MAX_LEAF_ENTRIES environmental variable. ", + flags = Flags.Design) + + max_node_bytes = Attribute("maxNodeBytes", + "Sets the CCNR_BTREE_MAX_NODE_BYTES environmental variable. ", + flags = Flags.Design) + + max_node_pool = Attribute("maxNodePool", + "Sets the CCNR_BTREE_MAX_NODE_POOL environmental variable. ", + flags = Flags.Design) + + content_cache = Attribute("contentCache", + "Sets the CCNR_CONTENT_CACHE environmental variable. ", + flags = Flags.Design) + + debug = Attribute("debug", + "Sets the CCNR_DEBUG environmental variable. " + "Logging level for ccnr. Defaults to WARNING.", + type = Types.Enumerate, + allowed = [ + "NONE", + "SEVERE", + "ERROR", + "WARNING", + "INFO", + "FINE, FINER, FINEST"], + flags = Flags.Design) + + directory = Attribute("directory", + "Sets the CCNR_DIRECTORY environmental variable. ", + flags = Flags.Design) + + global_prefix = Attribute("globalPrefix", + "Sets the CCNR_GLOBAL_PREFIX environmental variable. ", + flags = Flags.Design) + + listen_on = Attribute("listenOn", + "Sets the CCNR_LISTEN_ON environmental variable. ", + flags = Flags.Design) + + min_send_bufsize = Attribute("minSendBufsize", + "Sets the CCNR_MIN_SEND_BUFSIZE environmental variable. ", + flags = Flags.Design) + + proto = Attribute("proto", + "Sets the CCNR_PROTO environmental variable. ", + flags = Flags.Design) + + status_port = Attribute("statusPort", + "Sets the CCNR_STATUS_PORT environmental variable. ", + flags = Flags.Design) + + start_write_scope_limit = Attribute("startWriteScopeLimit", + "Sets the CCNR_START_WRITE_SCOPE_LIMIT environmental variable. ", + flags = Flags.Design) + + ccns_debug = Attribute("ccnsDebug", + "Sets the CCNS_DEBUG environmental variable. ", + flags = Flags.Design) + + ccns_enable = Attribute("ccnsEnable", + "Sets the CCNS_ENABLE environmental variable. ", + flags = Flags.Design) + + ccns_faux_error = Attribute("ccnsFauxError", + "Sets the CCNS_FAUX_ERROR environmental variable. ", + flags = Flags.Design) + + ccns_heartbeat_micros = Attribute("ccnsHeartBeatMicros", + "Sets the CCNS_HEART_BEAT_MICROS environmental variable. ", + flags = Flags.Design) + + ccns_max_compares_busy = Attribute("ccnsMaxComparesBusy", + "Sets the CCNS_MAX_COMPARES_BUSY environmental variable. ", + flags = Flags.Design) + + ccns_max_fetch_busy = Attribute("ccnsMaxFetchBusy", + "Sets the CCNS_MAX_FETCH_BUSY environmental variable. ", + flags = Flags.Design) + + ccns_node_fetch_lifetime = Attribute("ccnsNodeFetchLifetime", + "Sets the CCNS_NODE_FETCH_LIFETIME environmental variable. ", + flags = Flags.Design) + + ccns_note_err = Attribute("ccnsNoteErr", + "Sets the CCNS_NOTE_ERR environmental variable. ", + flags = Flags.Design) + + ccns_repo_store = Attribute("ccnsRepoStore", + "Sets the CCNS_REPO_STORE environmental variable. ", + flags = Flags.Design) + + ccns_root_advise_fresh = Attribute("ccnsRootAdviseFresh", + "Sets the CCNS_ROOT_ADVISE_FRESH environmental variable. ", + flags = Flags.Design) + + ccns_root_advise_lifetime = Attribute("ccnsRootAdviseLifetime", + "Sets the CCNS_ROOT_ADVISE_LIFETIME environmental variable. ", + flags = Flags.Design) + + ccns_stable_enabled = Attribute("ccnsStableEnabled", + "Sets the CCNS_STABLE_ENABLED environmental variable. ", + flags = Flags.Design) + + ccns_sync_scope = Attribute("ccnsSyncScope", + "Sets the CCNS_SYNC_SCOPE environmental variable. ", + flags = Flags.Design) + + repo_file = Attribute("repoFile1", + "The Repository uses $CCNR_DIRECTORY/repoFile1 for " + "persistent storage of CCN Content Objects", + flags = Flags.Design) + + cls._register_attribute(max_fanout) + cls._register_attribute(max_leaf_entries) + cls._register_attribute(max_node_bytes) + cls._register_attribute(max_node_pool) + cls._register_attribute(content_cache) + cls._register_attribute(debug) + cls._register_attribute(directory) + cls._register_attribute(global_prefix) + cls._register_attribute(listen_on) + cls._register_attribute(min_send_bufsize) + cls._register_attribute(proto) + cls._register_attribute(status_port) + cls._register_attribute(start_write_scope_limit) + cls._register_attribute(ccns_debug) + cls._register_attribute(ccns_enable) + cls._register_attribute(ccns_faux_error) + cls._register_attribute(ccns_heartbeat_micros) + cls._register_attribute(ccns_max_compares_busy) + cls._register_attribute(ccns_max_fetch_busy) + cls._register_attribute(ccns_node_fetch_lifetime) + cls._register_attribute(ccns_note_err) + cls._register_attribute(ccns_repo_store) + cls._register_attribute(ccns_root_advise_fresh) + cls._register_attribute(ccns_root_advise_lifetime) + cls._register_attribute(ccns_stable_enabled) + cls._register_attribute(ccns_sync_scope) + cls._register_attribute(repo_file) + + @classmethod + def _register_traces(cls): + log = Trace("log", "CCND log output") + + cls._register_trace(log) + + def __init__(self, ec, guid): + super(LinuxCCNR, self).__init__(ec, guid) + self._home = "ccnr-%s" % self.guid + + @property +
[docs] def ccnd(self): + ccnd = self.get_connected(LinuxCCND.get_rtype()) + if ccnd: return ccnd[0] + return None +
+ @property +
[docs] def node(self): + if self.ccnd: return self.ccnd.node + return None +
+
[docs] def do_deploy(self): + if not self.ccnd or self.ccnd.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- CCND state %s " % self.ccnd.state ) + + # ccnr needs to wait until ccnd is deployed and running + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", self._environment) + + command = self.get("command") + + self.info("Deploying command '%s' " % command) + + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + if self.get("repoFile1"): + # upload repoFile1 + local_file = self.get("repoFile1") + remote_file = "${RUN_HOME}/repoFile1" + remote_file = self.replace_paths(remote_file) + self.node.upload(local_file, + remote_file, + overwrite = False) + + # We want to make sure the repository 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.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = False, + env = env) +
+
[docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+ @property + def _start_command(self): + return "ccnr &" + + @property + def _environment(self): + envs = dict({ + "maxFanout": "CCNR_BTREE_MAX_FANOUT", + "maxLeafEntries": "CCNR_BTREE_MAX_LEAF_ENTRIES", + "maxNodeBytes": "CCNR_BTREE_MAX_NODE_BYTES", + "maxNodePool": "CCNR_BTREE_MAX_NODE_POOL", + "contentCache": "CCNR_CONTENT_CACHE", + "debug": "CCNR_DEBUG", + "directory": "CCNR_DIRECTORY", + "globalPrefix": "CCNR_GLOBAL_PREFIX", + "listenOn": "CCNR_LISTEN_ON", + "minSendBufsize": "CCNR_MIN_SEND_BUFSIZE", + "proto": "CCNR_PROTO", + "statusPort": "CCNR_STATUS_PORT", + "startWriteScopeLimit": "CCNR_START_WRITE_SCOPE_LIMIT", + "ccnsDebug": "CCNS_DEBUG", + "ccnsEnable": "CCNS_ENABLE", + "ccnsFauxError": "CCNS_FAUX_ERROR", + "ccnsHeartBeatMicros": "CCNS_HEART_BEAT_MICROS", + "ccnsMaxComparesBusy": "CCNS_MAX_COMPARES_BUSY", + "ccnsMaxFetchBusy": "CCNS_MAX_FETCH_BUSY", + "ccnsNodeFetchLifetime": "CCNS_NODE_FETCH_LIFETIME", + "ccnsNoteErr": "CCNS_NOTE_ERR", + "ccnsRepoStore": "CCNS_REPO_STORE", + "ccnsRootAdviseFresh": "CCNS_ROOT_ADVISE_FRESH", + "ccnsRootAdviseLifetime": "CCNS_ROOT_ADVISE_LIFETIME", + "ccnsStableEnabled": "CCNS_STABLE_ENABLED", + "ccnsSyncScope": "CCNS_SYNC_SCOPE", + }) + + env = self.ccnd.path + env += " ".join(map(lambda k: "%s=%s" % (envs.get(k), self.get(k)) \ + if self.get(k) else "", envs.keys())) + + return env + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/fibentry.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/fibentry.html new file mode 100644 index 00000000..240329e9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ccn/fibentry.html @@ -0,0 +1,367 @@ + + + + + + + + nepi.resources.linux.ccn.fibentry — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ccn.fibentry

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 clsinit_copy, ResourceState, \
+    ResourceAction
+from nepi.resources.linux.application import LinuxApplication
+from nepi.resources.linux.ccn.ccnd import LinuxCCND
+from nepi.util.timefuncs import tnow
+
+import os
+import socket
+import time
+
+
+# TODO: Add rest of options for ccndc!!!
+#       Implement ENTRY DELETE!!
+
+@clsinit_copy
+
[docs]class LinuxFIBEntry(LinuxApplication): + _rtype = "linux::FIBEntry" + + @classmethod + def _register_attributes(cls): + uri = Attribute("uri", + "URI prefix to match and route for this FIB entry", + default = "ccnx:/", + flags = Flags.Design) + + protocol = Attribute("protocol", + "Transport protocol used in network connection to peer " + "for this FIB entry. One of 'udp' or 'tcp'.", + type = Types.Enumerate, + default = "udp", + allowed = ["udp", "tcp"], + flags = Flags.Design) + + host = Attribute("host", + "Peer hostname used in network connection for this FIB entry. ", + flags = Flags.Design) + + port = Attribute("port", + "Peer port address used in network connection to peer " + "for this FIB entry.", + flags = Flags.Design) + + ip = Attribute("ip", + "Peer host public IP used in network connection for this FIB entry. ", + flags = Flags.Design) + + cls._register_attribute(uri) + cls._register_attribute(protocol) + cls._register_attribute(host) + cls._register_attribute(port) + cls._register_attribute(ip) + + @classmethod + def _register_traces(cls): + ping = Trace("ping", "Ping to the peer end") + mtr = Trace("mtr", "Mtr to the peer end") + traceroute = Trace("traceroute", "Tracerout to the peer end") + + cls._register_trace(ping) + cls._register_trace(mtr) + cls._register_trace(traceroute) + + def __init__(self, ec, guid): + super(LinuxFIBEntry, self).__init__(ec, guid) + self._home = "fib-%s" % self.guid + self._ping = None + self._traceroute = None + self._ccnd = None + + @property +
[docs] def ccnd(self): + if not self._ccnd: + ccnd = self.get_connected(LinuxCCND.get_rtype()) + if ccnd: + self._ccnd = ccnd[0] + + return self._ccnd +
+ @property +
[docs] def ping(self): + if not self._ping: + from nepi.resources.linux.ping import LinuxPing + ping = self.get_connected(LinuxPing.get_rtype()) + if ping: + self._ping = ping[0] + + return self._ping +
+ @property +
[docs] def traceroute(self): + if not self._traceroute: + from nepi.resources.linux.traceroute import LinuxTraceroute + traceroute = self.get_connected(LinuxTraceroute.get_rtype()) + if traceroute: + self._traceroute = traceroute[0] + + return self._traceroute +
+ @property +
[docs] def node(self): + if self.ccnd: return self.ccnd.node + return None +
+
[docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + if name == "ping": + if not self.ping: + return None + return self.ec.trace(self.ping.guid, "stdout", attr, block, offset) + + if name == "traceroute": + if not self.traceroute: + return None + return self.ec.trace(self.traceroute.guid, "stdout", attr, block, offset) + + return super(LinuxFIBEntry, self).trace(name, attr, block, offset) +
+
[docs] def do_deploy(self): + # Wait until associated ccnd is provisioned + if not self.ccnd or self.ccnd.state < ResourceState.READY: + # ccnr needs to wait until ccnd is deployed and running + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("ip"): + host = self.get("host") + ip = socket.gethostbyname(host) + self.set("ip", ip) + + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", self._environment) + + command = self.get("command") + + self.info("Deploying command '%s' " % command) + + self.do_discover() + self.do_provision() + self.configure() + + self.set_ready() +
+
[docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + # We want to make sure the FIB entries are created + # before the experiment starts. + # Run the command as a bash script in the background, + # in the host ( but wait until the command has + # finished to continue ) + env = env and self.replace_paths(env) + command = self.replace_paths(command) + + # ccndc seems to return exitcode OK even if a (dns) error + # occurred, so we need to account for this case here. + (out, err), proc = self.execute_command(command, + env, blocking = True) + + if proc.poll(): + msg = "Failed to execute command" + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def configure(self): + if self.trace_enabled("ping") and not self.ping: + self.info("Configuring PING trace") + ping = self.ec.register_resource("linux::Ping") + self.ec.set(ping, "printTimestamp", True) + self.ec.set(ping, "target", self.get("host")) + self.ec.set(ping, "earlyStart", True) + self.ec.register_connection(ping, self.node.guid) + self.ec.register_connection(ping, self.guid) + # schedule ping deploy + self.ec.deploy(guids=[ping], group = self.deployment_group) + + if self.trace_enabled("traceroute") and not self.traceroute: + self.info("Configuring TRACEROUTE trace") + traceroute = self.ec.register_resource("linux::Traceroute") + self.ec.set(traceroute, "printTimestamp", True) + self.ec.set(traceroute, "continuous", True) + self.ec.set(traceroute, "target", self.get("host")) + self.ec.set(traceroute, "earlyStart", True) + self.ec.register_connection(traceroute, self.node.guid) + self.ec.register_connection(traceroute, self.guid) + # schedule mtr deploy + self.ec.deploy(guids=[traceroute], group = self.deployment_group) +
+
[docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_stop(self): + command = self.get('command') + env = self.get('env') + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % command) + + command = self._stop_command + (out, err), proc = self.execute_command(command, env, + blocking = True) + + self.set_stopped() + + if err: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+ @property + def _start_command(self): + uri = self.get("uri") or "" + protocol = self.get("protocol") or "" + ip = self.get("ip") or "" + port = self.get("port") or "" + + # add ccnx:/example.com/ udp 224.0.0.204 52428 + return "ccndc add %(uri)s %(protocol)s %(host)s %(port)s" % ({ + "uri" : uri, + "protocol": protocol, + "host": ip, + "port": port + }) + + @property + def _stop_command(self): + uri = self.get("uri") or "" + protocol = self.get("protocol") or "" + ip = self.get("ip") or "" + port = self.get("port") or "" + + # add ccnx:/example.com/ udp 224.0.0.204 52428 + return "ccndc del %(uri)s %(protocol)s %(host)s %(port)s" % ({ + "uri" : uri, + "protocol": protocol, + "host": ip, + "port": port + }) + + @property + def _environment(self): + return self.ccnd.path + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/channel.html new file mode 100644 index 00000000..171732c5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/channel.html @@ -0,0 +1,129 @@ + + + + + + + + nepi.resources.linux.channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 ResourceManager, clsinit_copy, \
+        ResourceState
+
+@clsinit_copy
+
[docs]class LinuxChannel(ResourceManager): + _rtype = "linux::Channel" + _help = "Represents a wireless channel on a network of Linux hosts" + _platform = "linux" + + def __init__(self, ec, guid): + super(LinuxChannel, self).__init__(ec, guid) + +
[docs] def log_message(self, msg): + return " guid %d - %s " % (self.guid, msg) +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/debfuncs.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/debfuncs.html new file mode 100644 index 00000000..c1e44985 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/debfuncs.html @@ -0,0 +1,133 @@ + + + + + + + + nepi.resources.linux.debfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.debfuncs

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+# TODO: Investigate using http://nixos.org/nix/
+
+
[docs]def install_packages_command(os, packages): + if not isinstance(packages, list): + packages = [packages] + + cmd = " && ".join(map(lambda p: + " { dpkg -s %(package)s || sudo -S apt-get -y install %(package)s ; } " % { + 'package': p}, packages)) + + #cmd = { dpkg -s vim || sudo -S apt-get -y install vim ; } && .. + return cmd +
+
[docs]def remove_packages_command(os, packages): + if not isinstance(packages, list): + packages = [packages] + + cmd = " && ".join(map(lambda p: + " { dpkg -s %(package)s && sudo -S apt-get -y purge %(package)s ; } " % { + 'package': p}, packages)) + + #cmd = { dpkg -s vim && sudo -S apt-get -y purge vim ; } && .. + return cmd +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/gretunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/gretunnel.html new file mode 100644 index 00000000..563f0b05 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/gretunnel.html @@ -0,0 +1,177 @@ + + + + + + + + nepi.resources.linux.gretunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.gretunnel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.tunnel import LinuxTunnel
+from nepi.util.sshfuncs import ProcStatus
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import re
+import socket
+import time
+import os
+
+@clsinit_copy
+
[docs]class LinuxGRETunnel(LinuxTunnel): + _rtype = "linux::GRETunnel" + _help = "Constructs a tunnel between two Linux endpoints using a UDP connection " + +
[docs] def log_message(self, msg): + return " guid %d - GRE tunnel %s - %s - %s " % (self.guid, + self.endpoint1.node.get("hostname"), + self.endpoint2.node.get("hostname"), + msg) +
+
[docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + connected = [] + for guid in self.connections: + rm = self.ec.get_resource(guid) + if hasattr(rm, "gre_connect"): + connected.append(rm) + return connected +
+
[docs] def initiate_connection(self, endpoint, remote_endpoint): + # Return the command to execute to initiate the connection to the + # other endpoint + connection_run_home = self.run_home(endpoint) + connection_app_home = self.app_home(endpoint) + data = endpoint.gre_connect(remote_endpoint, + connection_app_home, + connection_run_home) + return data +
+
[docs] def establish_connection(self, endpoint, remote_endpoint, data): + pass +
+
[docs] def verify_connection(self, endpoint, remote_endpoint): + remote_ip = socket.gethostbyname(remote_endpoint.node.get("hostname")) + + command = "ping -c 4 %s" % remote_ip + (out, err), proc = endpoint.node.execute(command, + blocking = True) + + m = re.search("(\d+)% packet loss", str(out)) + if not m or int(m.groups()[0]) == 100: + msg = " Error establishing GRE Tunnel" + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def terminate_connection(self, endpoint, remote_endpoint): + pass +
+
[docs] def check_state_connection(self): + pass +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/interface.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/interface.html new file mode 100644 index 00000000..d1a91d19 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/interface.html @@ -0,0 +1,402 @@ + + + + + + + + nepi.resources.linux.interface — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.interface

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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, Types, Flags
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.resources.linux.node import LinuxNode
+from nepi.resources.linux.channel import LinuxChannel
+
+import collections
+import os
+import random
+import re
+import tempfile
+import time
+
+# TODO: 
+#     - check UP, MTU attributes!
+#     - clean up code and test!
+
+@clsinit_copy
+
[docs]class LinuxInterface(ResourceManager): + _rtype = "linux::Interface" + _help = "Controls network devices on Linux hosts through the ifconfig tool" + _platform = "linux" + + @classmethod + def _register_attributes(cls): + ip4 = Attribute("ip4", "IPv4 Address", + flags = Flags.Design) + + ip6 = Attribute("ip6", "IPv6 Address", + flags = Flags.Design) + + mac = Attribute("mac", "MAC Address", + flags = Flags.Design) + + mask4 = Attribute("mask4", "IPv4 network mask", + flags = Flags.Design) + + mask6 = Attribute("mask6", "IPv6 network mask", + type = Types.Integer, + 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.Design) + + up = Attribute("up", "Link up", type = Types.Bool) + + tear_down = Attribute("tearDown", "Bash script to be executed before " + \ + "releasing the resource", + flags = Flags.Design) + + cls._register_attribute(ip4) + cls._register_attribute(ip6) + cls._register_attribute(mac) + cls._register_attribute(mask4) + cls._register_attribute(mask6) + cls._register_attribute(mtu) + cls._register_attribute(devname) + cls._register_attribute(up) + cls._register_attribute(tear_down) + + def __init__(self, ec, guid): + super(LinuxInterface, self).__init__(ec, guid) + self._configured = False + + self.add_set_hooks() + +
[docs] def log_message(self, msg): + return " guid %d - host %s - %s " % (self.guid, + self.node.get("hostname"), msg) +
+ @property +
[docs] def node(self): + node = self.get_connected(LinuxNode.get_rtype()) + if node: return node[0] + return None +
+ @property +
[docs] def channel(self): + chan = self.get_connected(LinuxChannel.get_rtype()) + if chan: return chan[0] + return None +
+
[docs] def do_discover(self): + devname = self.get("deviceName") + ip4 = self.get("ip4") + ip6 = self.get("ip4") + mac = self.get("mac") + mask4 = self.get("mask4") + mask6 = self.get("mask6") + mtu = self.get("mtu") + + # Get current interfaces information + (out, err), proc = self.node.execute("ifconfig", sudo = True, tty = True) + + if err and proc.poll(): + msg = " Error retrieving interface information " + self.error(msg, out, err) + raise RuntimeError, "%s - %s - %s" % (msg, out, err) + + # Check if an interface is found matching the RM attributes + ifaces = out.split("\n\n") + + for i in ifaces: + m = re.findall("(\w+)\s+Link\s+encap:\w+(\s+HWaddr\s+(([0-9a-fA-F]{2}:?){6}))?(\s+inet\s+addr:((\d+\.?){4}).+Mask:(\d+\.\d+\.\d+\.\d+))?(.+inet6\s+addr:\s+([0-9a-fA-F:.]+)/(\d+))?(.+(UP))?(.+MTU:(\d+))?", i, re.DOTALL) + + m = m[0] + dn = m[0] + mc = m[2] + i4 = m[5] + msk4 = m[7] + i6 = m[9] + msk6 = m[10] + up = True if m[12] else False + mu = m[14] + + self.debug("Found interface %(devname)s with MAC %(mac)s," + "IPv4 %(ipv4)s %(mask4)s IPv6 %(ipv6)s/%(mask6)s %(up)s %(mtu)s" % ({ + 'devname': dn, + 'mac': mc, + 'ipv4': i4, + 'mask4': msk4, + 'ipv6': i6, + 'mask6': msk6, + 'up': up, + 'mtu': mu + }) ) + + # If the user didn't provide information we take the first + # interface that is UP + if not devname and not ip4 and not ip6 and up: + self._configured = True + self.load_configuration(dn, mc, i4, msk4, i6, msk6, mu, up) + break + + # If the user provided ipv4 or ipv6 matching that of an interface + # load the interface info + if (ip4 and ip4 == i4) or (ip6 and ip6 == i6): + self._configured = True + self.load_configuration(dn, mc, i4, msk4, i6, msk6, mu, up) + break + + # If the user provided the device name we load the associated info + if devname and devname == dn: + if ((ip4 and ip4 == i4) and (ipv6 and ip6 == i6)) or \ + not (ip4 or ip6): + self._configured = True + + # If the user gave a different ip than the existing, asume ip + # needs to be changed + i4 = ip4 or i4 + i6 = ip6 or i6 + mu = mtu or mu + + self.load_configuration(dn, mc, i4, msk4, i6, msk6, mu, up) + break + + if not self.get("deviceName"): + msg = "Unable to resolve interface " + self.error(msg) + raise RuntimeError, msg + + super(LinuxInterface, self).do_discover() +
+
[docs] def do_provision(self): + devname = self.get("deviceName") + ip4 = self.get("ip4") + ip6 = self.get("ip4") + mac = self.get("mac") + mask4 = self.get("mask4") + mask6 = self.get("mask6") + mtu = self.get("mtu") + + # Must configure interface if configuration is required + if not self._configured: + cmd = "ifconfig %s" % devname + + if ip4 and mask4: + cmd += " %(ip4)s netmask %(mask4)s broadcast %(bcast)s up" % ({ + 'ip4': ip4, + 'mask4': mask4, + 'bcast': bcast}) + if mtu: + cmd += " mtu %d " % mtu + + (out, err), proc = self.node.execute(cmd, sudo = True) + + if err and proc.poll(): + msg = "Error configuring interface with command '%s'" % cmd + self.error(msg, out, err) + raise RuntimeError, "%s - %s - %s" % (msg, out, err) + + if ip6 and mask6: + cmd = "ifconfig %(devname)s inet6 add %(ip6)s/%(mask6)d" % ({ + 'devname': devname, + 'ip6': ip6, + 'mask6': mask6}) + + (out, err), proc = self.node.execute(cmd, sudo = True) + + if err and proc.poll(): + msg = "Error seting ipv6 for interface using command '%s' " % cmd + self.error(msg, out, err) + raise RuntimeError, "%s - %s - %s" % (msg, out, err) + + super(LinuxInterface, self).do_provision() +
+
[docs] def do_deploy(self): + # Wait until node is provisioned + node = self.node + chan = self.channel + + if not node or node.state < ResourceState.PROVISIONED: + self.ec.schedule(self.reschedule_delay, self.deploy) + elif not chan or chan.state < ResourceState.READY: + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + # Verify if the interface exists in node. If not, configue + # if yes, load existing configuration + self.do_discover() + self.do_provision() + + super(LinuxInterface, self).do_deploy() +
+
[docs] def do_release(self): + tear_down = self.get("tearDown") + if tear_down: + self.execute(tear_down) + + super(LinuxInterface, self).do_release() +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+
[docs] def load_configuration(self, devname, mac, ip4, mask4, ip6, mask6, mtu, up): + self.set("deviceName", devname) + self.set("mac", mac) + self.set("ip4", ip4) + self.set("mask4", mask4) + self.set("ip6", ip6) + self.set("mask6", mask6) + + # set the following without validating or triggering hooks + attr = self._attrs["up"] + attr._value = up + attr = self._attrs["mtu"] + attr._value = mtu +
+
[docs] def add_set_hooks(self): + attrup = self._attrs["up"] + attrup.set_hook = self.set_hook_up + + attrmtu = self._attrs["mtu"] + attrmtu.set_hook = self.set_hook_mtu +
+
[docs] def set_hook_up(self, oldval, newval): + if self.state == ResourceState.NEW or oldval == newval: + return oldval + + # configure interface up + if newval == True: + cmd = "ifup %s" % self.get("deviceName") + elif newval == False: + cmd = "ifdown %s" % self.get("deviceName") + + (out, err), proc = self.node.execute(cmd, sudo = True) + + if err and proc.poll(): + msg = "Error setting interface up/down using command '%s' " % cmd + self.error(msg, err, out) + return oldval + + return newval +
+
[docs] def set_hook_mtu(self, oldval, newval): + if self.state == ResourceState.NEW or oldval == newval: + return oldval + + cmd = "ifconfig %s mtu %d" % (self.get("deviceName"), newval) + + (out, err), proc = self.node.execute(cmd, sudo = True) + + if err and proc.poll(): + msg = "Error setting interface MTU using command '%s' " % cmd + self.error(msg, err, out) + return oldval + + return newval +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/mtr.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/mtr.html new file mode 100644 index 00000000..b7ff738e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/mtr.html @@ -0,0 +1,240 @@ + + + + + + + + nepi.resources.linux.mtr — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.mtr

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 
+from nepi.resources.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxMtr(LinuxApplication): + _rtype = "linux::Mtr" + + @classmethod + def _register_attributes(cls): + report_cycles = Attribute("reportCycles", + "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.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.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.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.Design) + + countinuous = Attribute("continuous", + "Run mtr in a while loop", + type = Types.Bool, + default = False, + flags = Flags.Design) + + print_timestamp = Attribute("printTimestamp", + "Print timestamp before running mtr", + type = Types.Bool, + default = False, + flags = Flags.Design) + + target = Attribute("target", + "mtr target host (host that will be pinged)", + flags = Flags.Design) + + early_start = Attribute("earlyStart", + "Start ping as early as deployment. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(report_cycles) + cls._register_attribute(no_dns) + cls._register_attribute(address) + cls._register_attribute(interval) + cls._register_attribute(countinuous) + cls._register_attribute(print_timestamp) + cls._register_attribute(target) + cls._register_attribute(early_start) + + def __init__(self, ec, guid): + super(LinuxMtr, self).__init__(ec, guid) + self._home = "mtr-%s" % self.guid + self._sudo_kill = True + +
[docs] def upload_start_command(self): + super(LinuxMtr, self).upload_start_command() + + if self.get("earlyStart") == True: + self._run_in_background() +
+
[docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", "PATH=$PATH:/usr/sbin/") + + if not self.get("depends"): + self.set("depends", "mtr") + + super(LinuxMtr, self).do_deploy() +
+
[docs] def do_start(self): + if self.get("earlyStart") == True: + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg + else: + super(LinuxMtr, self).do_start() +
+ @property + def _start_command(self): + args = [] + if self.get("continuous") == True: + args.append("while true; do ") + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + args.append("sudo -S mtr --report") + if self.get("reportCycles"): + args.append("-c %s" % self.get("reportCycles")) + if self.get("noDns") == True: + args.append("-n") + if self.get("address"): + args.append("-a %s" % self.get("address")) + args.append(self.get("target")) + if self.get("continuous") == True: + args.append("; done ") + + command = " ".join(args) + + return command + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsclient.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsclient.html new file mode 100644 index 00000000..63d53cc8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsclient.html @@ -0,0 +1,198 @@ + + + + + + + + nepi.resources.linux.netns.netnsclient — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.netns.netnsclient

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.netns.netnsclient import NetNSClient
+from nepi.resources.netns.netnsserver import NetNSWrapperMessage
+
+
[docs]class LinuxNetNSClient(NetNSClient): + def __init__(self, emulation): + super(LinuxNetNSClient, self).__init__() + self._emulation = weakref.ref(emulation) + + self._socat_proc = None + + @property +
[docs] def emulation(self): + return self._emulation() +
+
[docs] 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.emulation.node.get("hostname") in ['localhost', '127.0.0.1']: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.emulation.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.emulation.remote_socket, + } + + (reply, err), proc = self.emulation.node.execute(command, + with_lock = True) + + if (err and proc.poll()) or reply.strip() == "": + msg = (" Couldn't connect to remote socket %s - REPLY: %s " + "- ERROR: %s ") % ( + self.emulation.remote_socket, reply, err) + self.emulation.error(msg, reply, err) + raise RuntimeError(msg) + + reply = cPickle.loads(base64.b64decode(reply)) + + return reply +
+
[docs] def create(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.CREATE, *args, **kwargs) +
+
[docs] def invoke(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.INVOKE, *args, **kwargs) +
+
[docs] def set(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.SET, *args, **kwargs) +
+
[docs] def get(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.GET, *args, **kwargs) +
+
[docs] def flush(self, *args, **kwargs): + return self.send_msg(NetNSWrapperMessage.FLUSH, *args, **kwargs) +
+
[docs] def shutdown(self, *args, **kwargs): + try: + return self.send_msg(NetNSWrapperMessage.SHUTDOWN, *args, **kwargs) + except: + pass + + return None +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsemulation.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsemulation.html new file mode 100644 index 00000000..1b3771eb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/netns/netnsemulation.html @@ -0,0 +1,473 @@ + + + + + + + + nepi.resources.linux.netns.netnsemulation — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.netns.netnsemulation

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow, tdiffsec
+from nepi.resources.netns.netnsemulation import NetNSEmulation
+from nepi.resources.linux.netns.netnsclient import LinuxNetNSClient
+
+import os
+import time
+import threading
+
+@clsinit_copy
+
[docs]class LinuxNetNSEmulation(LinuxApplication, NetNSEmulation): + _rtype = "linux::netns::Emulation" + + @classmethod + def _register_attributes(cls): + verbose = Attribute("verbose", + "True to output debugging info for the client-server communication", + type = Types.Bool, + flags = Flags.Design) + + enable_dump = Attribute("enableDump", + "Enable dumping the remote executed commands to a script " + "in order to later reproduce and debug the experiment", + type = Types.Bool, + default = False, + flags = Flags.Design) + + version = Attribute("version", + "Version of netns to install from nsam repo", + default = "netns-dev", + flags = Flags.Design) + + cls._register_attribute(enable_dump) + cls._register_attribute(verbose) + cls._register_attribute(version) + + def __init__(self, ec, guid): + LinuxApplication.__init__(self, ec, guid) + NetNSEmulation.__init__(self) + + self._client = None + self._home = "netns-emu-%s" % self.guid + self._socket_name = "netns-%s.sock" % os.urandom(4).encode('hex') + + @property +
[docs] def socket_name(self): + return self._socket_name +
+ @property +
[docs] def remote_socket(self): + return os.path.join(self.run_home, self.socket_name) +
+
[docs] def upload_sources(self): + self.node.mkdir(os.path.join(self.node.src_dir, "netnswrapper")) + + # upload wrapper python script + wrapper = os.path.join(os.path.dirname(__file__), "..", "..", "netns", + "netnswrapper.py") + + self.node.upload(wrapper, + os.path.join(self.node.src_dir, "netnswrapper", "netnswrapper.py"), + overwrite = False) + + # upload wrapper debug python script + wrapper_debug = os.path.join(os.path.dirname(__file__), "..", "..", "netns", + "netnswrapper_debug.py") + + self.node.upload(wrapper_debug, + os.path.join(self.node.src_dir, "netnswrapper", "netnswrapper_debug.py"), + overwrite = False) + + # upload server python script + server = os.path.join(os.path.dirname(__file__), "..", "..", "netns", + "netnsserver.py") + + self.node.upload(server, + os.path.join(self.node.src_dir, "netnswrapper", "netnsserver.py"), + overwrite = False) + + # Upload user defined sources + self.node.mkdir(os.path.join(self.node.src_dir, "netns")) + src_dir = os.path.join(self.node.src_dir, "netns") + + super(LinuxNetNSEmulation, self).upload_sources(src_dir = src_dir) +
+
[docs] def upload_extra_sources(self, sources = None, src_dir = None): + return super(LinuxNetNSEmulation, self).upload_sources( + sources = sources, + src_dir = src_dir) +
+
[docs] def upload_start_command(self): + command = self.get("command") + env = self.get("env") + + # We want to make sure the emulator 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 wrapper + self._run_in_background() + + # Wait until the remote socket is created + self.wait_remote_socket() +
+
[docs] 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(self.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("version", version) + self.set("sources", source) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("env"): + self.set("env", self._environment) + + self.do_discover() + self.do_provision() + + # Create client + self._client = LinuxNetNSClient(self) + + self.set_ready() +
+
[docs] def do_start(self): + """ Starts execution execution + + """ + self.info("Starting") + + if self.state == ResourceState.READY: + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_stop(self): + """ Stops simulation execution + + """ + if self.state == ResourceState.STARTED: + self.set_stopped() +
+
[docs] 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("sudo") + command.append("PYTHONPATH=$PYTHONPATH:${SRC}/netnswrapper/") + command.append("python ${SRC}/netnswrapper/netnsserver.py -S %s" % \ + os.path.basename(self.remote_socket) ) + + if self.get("enableDump"): + command.append("-D") + + if self.get("verbose"): + command.append("-v") + + command = " ".join(command) + return command + + @property + def _dependencies(self): + if self.node.use_rpm: + return (" python python-devel mercurial unzip bridge-utils iproute") + elif self.node.use_deb: + return (" python python-dev mercurial unzip bridge-utils iproute") + return "" + + @property +
[docs] def netns_repo(self): + return "http://nepi.inria.fr/code/netns" +
+ @property +
[docs] def netns_version(self): + version = self.get("version") + return version or "dev" +
+ @property +
[docs] def python_unshare_repo(self): + return "http://nepi.inria.fr/code/python-unshare" +
+ @property +
[docs] def python_unshare_version(self): + return "dev" +
+ @property +
[docs] def python_passfd_repo(self): + return "http://nepi.inria.fr/code/python-passfd" +
+ @property +
[docs] def python_passfd_version(self): + return "dev" +
+ @property +
[docs] def netns_src(self): + location = "${SRC}/netns/%(version)s" \ + % { + "version": self.netns_version, + } + + return location +
+ @property +
[docs] def python_unshare_src(self): + location = "${SRC}/python_unshare/%(version)s" \ + % { + "version": self.python_unshare_version, + } + + return location +
+ @property +
[docs] def python_passfd_src(self): + location = "${SRC}/python_passfd/%(version)s" \ + % { + "version": self.python_passfd_version, + } + + return location +
+
[docs] def clone_command(self, name, repo, src): + clone_cmd = ( + # Test if alredy cloned + " ( " + " ( " + " ( test -d %(src)s ) " + " && echo '%(name)s binaries found, nothing to do'" + " ) " + " ) " + " || " + # clone source code + " ( " + " mkdir -p %(src)s && " + " hg clone %(repo)s %(src)s" + " ) " + ) % { + "repo": repo, + "src": src, + "name": name, + } + + return clone_cmd +
+ @property + def _build(self): + netns_clone = self.clone_command("netns", self.netns_repo, + self.netns_src) + python_unshare_clone = self.clone_command("python_unshare", + self.python_unshare_repo, self.python_unshare_src) + python_passfd_clone = self.clone_command("python_passfd", + self.python_passfd_repo, self.python_passfd_src) + + build_cmd = ( + # Netns installation + "( %(netns_clone)s )" + " && " + "( %(python_unshare_clone)s )" + " && " + "( %(python_passfd_clone)s )" + ) % { + "netns_clone": netns_clone, + "python_unshare_clone": python_unshare_clone, + "python_passfd_clone": python_passfd_clone, + } + + return build_cmd + + @property + def _environment(self): + env = [] + env.append("PYTHONPATH=$PYTHONPAH:%(netns_src)s/src/:%(python_unshare_src)s/src:%(python_passfd_src)s/src}" % { + "netns_src": self.netns_src, + "python_unshare_src": self.python_unshare_src, + "python_passfd_src": self.python_passfd_src, + }) + + return " ".join(env) + +
[docs] 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) + ) +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+
[docs] def wait_remote_socket(self): + """ Waits until the remote socket is created + """ + command = " [ -e %s ] && echo 'DONE' " % self.remote_socket + + for i in xrange(200): + (out, err), proc = self.node.execute(command, retry = 1, + with_lock = True) + + if out.find("DONE") > -1: + break + else: + raise RuntimeError("Remote socket not found at %s" % \ + self.remote_socket) + +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/node.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/node.html new file mode 100644 index 00000000..84bc1c1b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/node.html @@ -0,0 +1,1216 @@ + + + + + + + + nepi.resources.linux.node — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.node

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.resources.linux import rpmfuncs, debfuncs 
+from nepi.util import sshfuncs, execfuncs
+from nepi.util.sshfuncs import ProcStatus
+
+import collections
+import os
+import random
+import re
+import tempfile
+import time
+import threading
+import traceback
+
+# TODO: Unify delays!!
+# TODO: Validate outcome of uploads!! 
+
+
[docs]class ExitCode: + """ + Error codes that the rexitcode function can return if unable to + check the exit code of a spawned process + """ + FILENOTFOUND = -1 + CORRUPTFILE = -2 + ERROR = -3 + OK = 0 +
+
[docs]class OSType: + """ + Supported flavors of Linux OS + """ + DEBIAN = 1 + UBUNTU = 1 << 1 + FEDORA = 1 << 2 + FEDORA_8 = 1 << 3 | FEDORA + FEDORA_12 = 1 << 4 | FEDORA + FEDORA_14 = 1 << 5 | FEDORA +
+@clsinit_copy +
[docs]class LinuxNode(ResourceManager): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + .. note:: + + There are different ways in which commands can be executed using the + LinuxNode interface (i.e. 'execute' - blocking and non blocking, 'run', + 'run_and_wait'). + + Brief explanation: + + * 'execute' (blocking mode) : + + HOW IT WORKS: 'execute', forks a process and run the + command, synchronously, attached to the terminal, in + foreground. + The execute method will block until the command returns + the result on 'out', 'err' (so until it finishes executing). + + USAGE: short-lived commands that must be executed attached + to a terminal and in foreground, for which it IS necessary + to block until the command has finished (e.g. if you want + to run 'ls' or 'cat'). + + * 'execute' (NON blocking mode - blocking = False) : + + HOW IT WORKS: Same as before, except that execute method + will return immediately (even if command still running). + + USAGE: long-lived commands that must be executed attached + to a terminal and in foreground, but for which it is not + necessary to block until the command has finished. (e.g. + start an application using X11 forwarding) + + * 'run' : + + HOW IT WORKS: Connects to the host ( using SSH if remote) + and launches the command in background, detached from any + terminal (daemonized), and returns. The command continues to + run remotely, but since it is detached from the terminal, + its pipes (stdin, stdout, stderr) can't be redirected to the + console (as normal non detached processes would), and so they + are explicitly redirected to files. The pidfile is created as + part of the process of launching the command. The pidfile + holds the pid and ppid of the process forked in background, + so later on it is possible to check whether the command is still + running. + + USAGE: long-lived commands that can run detached in background, + for which it is NOT necessary to block (wait) until the command + has finished. (e.g. start an application that is not using X11 + forwarding. It can run detached and remotely in background) + + * 'run_and_wait' : + + HOW IT WORKS: Similar to 'run' except that it 'blocks' until + the command has finished execution. It also checks whether + errors occurred during runtime by reading the exitcode file, + which contains the exit code of the command that was run + (checking stderr only is not always reliable since many + commands throw debugging info to stderr and the only way to + automatically know whether an error really happened is to + check the process exit code). + + Another difference with respect to 'run', is that instead + of directly executing the command as a bash command line, + it uploads the command to a bash script and runs the script. + This allows to use the bash script to debug errors, since + it remains at the remote host and can be run manually to + reproduce the error. + + USAGE: medium-lived commands that can run detached in + background, for which it IS necessary to block (wait) until + the command has finished. (e.g. Package installation, + source compilation, file download, etc) + + """ + _rtype = "linux::Node" + _help = "Controls Linux host machines ( either localhost or a host " \ + "that can be accessed using a SSH key)" + _platform = "linux" + + @classmethod + def _register_attributes(cls): + hostname = Attribute("hostname", "Hostname of the machine", + flags = Flags.Design) + + username = Attribute("username", "Local account username", + flags = Flags.Credential) + + port = Attribute("port", "SSH port", flags = Flags.Design) + + home = Attribute("home", + "Experiment home directory to store all experiment related files", + flags = Flags.Design) + + identity = Attribute("identity", "SSH identity file", + flags = Flags.Credential) + + server_key = Attribute("serverKey", "Server public key", + 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.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.Design) + + clean_processes = Attribute("cleanProcesses", + "Kill all running processes before starting experiment", + type = Types.Bool, + default = False, + flags = Flags.Design) + + tear_down = Attribute("tearDown", "Bash script to be executed before " + \ + "releasing the resource", + flags = Flags.Design) + + gateway_user = Attribute("gatewayUser", "Gateway account username", + flags = Flags.Design) + + gateway = Attribute("gateway", "Hostname of the gateway machine", + flags = Flags.Design) + + ip = Attribute("ip", "Linux host public IP address. " + "Must not be modified by the user unless hostname is 'localhost'", + flags = Flags.Design) + + cls._register_attribute(hostname) + cls._register_attribute(username) + cls._register_attribute(port) + cls._register_attribute(home) + cls._register_attribute(identity) + cls._register_attribute(server_key) + cls._register_attribute(clean_home) + cls._register_attribute(clean_experiment) + cls._register_attribute(clean_processes) + cls._register_attribute(tear_down) + cls._register_attribute(gateway_user) + cls._register_attribute(gateway) + cls._register_attribute(ip) + + def __init__(self, ec, guid): + super(LinuxNode, self).__init__(ec, guid) + self._os = None + # home directory at Linux host + self._home_dir = "" + + # lock to prevent concurrent applications on the same node, + # to execute commands at the same time. There are potential + # concurrency issues when using SSH to a same host from + # multiple threads. There are also possible operational + # issues, e.g. an application querying the existence + # of a file or folder prior to its creation, and another + # application creating the same file or folder in between. + self._node_lock = threading.Lock() + +
[docs] def log_message(self, msg): + return " guid %d - host %s - %s " % (self.guid, + self.get("hostname"), msg) +
+ @property +
[docs] def home_dir(self): + home = self.get("home") or "" + if not home.startswith("/"): + home = os.path.join(self._home_dir, home) + return home +
+ @property +
[docs] def nepi_home(self): + return os.path.join(self.home_dir, ".nepi") +
+ @property +
[docs] def usr_dir(self): + return os.path.join(self.nepi_home, "nepi-usr") +
+ @property +
[docs] def lib_dir(self): + return os.path.join(self.usr_dir, "lib") +
+ @property +
[docs] def bin_dir(self): + return os.path.join(self.usr_dir, "bin") +
+ @property +
[docs] def src_dir(self): + return os.path.join(self.usr_dir, "src") +
+ @property +
[docs] def share_dir(self): + return os.path.join(self.usr_dir, "share") +
+ @property +
[docs] def exp_dir(self): + return os.path.join(self.nepi_home, "nepi-exp") +
+ @property +
[docs] def exp_home(self): + return os.path.join(self.exp_dir, self.ec.exp_id) +
+ @property +
[docs] def node_home(self): + return os.path.join(self.exp_home, "node-%d" % self.guid) +
+ @property +
[docs] def run_home(self): + return os.path.join(self.node_home, self.ec.run_id) +
+ @property +
[docs] def os(self): + if self._os: + return self._os + + if not self.localhost and not self.get("username"): + msg = "Can't resolve OS, insufficient data " + self.error(msg) + raise RuntimeError, msg + + out = self.get_os() + + if out.find("Debian") == 0: + self._os = OSType.DEBIAN + elif out.find("Ubuntu") ==0: + self._os = OSType.UBUNTU + elif out.find("Fedora release") == 0: + self._os = OSType.FEDORA + if out.find("Fedora release 8") == 0: + self._os = OSType.FEDORA_8 + elif out.find("Fedora release 12") == 0: + self._os = OSType.FEDORA_12 + elif out.find("Fedora release 14") == 0: + self._os = OSType.FEDORA_14 + else: + msg = "Unsupported OS" + self.error(msg, out) + raise RuntimeError, "%s - %s " %( msg, out ) + + return self._os +
+
[docs] def get_os(self): + # The underlying SSH layer will sometimes return an empty + # output (even if the command was executed without errors). + # To work arround this, repeat the operation N times or + # until the result is not empty string + out = "" + try: + (out, err), proc = self.execute("cat /etc/issue", + with_lock = True, + blocking = True) + except: + trace = traceback.format_exc() + msg = "Error detecting OS: %s " % trace + self.error(msg, out, err) + + return out +
+ @property +
[docs] def use_deb(self): + return (self.os & (OSType.DEBIAN|OSType.UBUNTU)) +
+ @property +
[docs] def use_rpm(self): + return (self.os & OSType.FEDORA) +
+ @property +
[docs] def localhost(self): + return self.get("hostname") in ['localhost', '127.0.0.1', '::1'] +
+
[docs] def do_provision(self): + # check if host is alive + if not self.is_alive(): + msg = "Deploy failed. Unresponsive node %s" % self.get("hostname") + self.error(msg) + raise RuntimeError, msg + + self.find_home() + + if self.get("cleanProcesses"): + self.clean_processes() + + if self.get("cleanHome"): + self.clean_home() + + if self.get("cleanExperiment"): + self.clean_experiment() + + # Create shared directory structure and node home directory + paths = [self.lib_dir, + self.bin_dir, + self.src_dir, + self.share_dir, + self.node_home] + + self.mkdir(paths) + + # Get Public IP address if possible + if not self.get("ip"): + try: + ip = sshfuncs.gethostbyname(self.get("hostname")) + self.set("ip", ip) + except: + if self.get("gateway") is None: + msg = "Local DNS can not resolve hostname %s" % self.get("hostname") + self.error(msg) + + super(LinuxNode, self).do_provision() +
+
[docs] def do_deploy(self): + if self.state == ResourceState.NEW: + self.info("Deploying node") + self.do_discover() + self.do_provision() + + # Node needs to wait until all associated interfaces are + # ready before it can finalize deployment + from nepi.resources.linux.interface import LinuxInterface + ifaces = self.get_connected(LinuxInterface.get_rtype()) + for iface in ifaces: + if iface.state < ResourceState.READY: + self.ec.schedule(self.reschedule_delay, self.deploy) + return + + super(LinuxNode, self).do_deploy() +
+
[docs] def do_release(self): + rms = self.get_connected() + for rm in rms: + # Node needs to wait until all associated RMs are released + # before it can be released + if rm.state != ResourceState.RELEASED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + tear_down = self.get("tearDown") + if tear_down: + self.execute(tear_down) + + self.clean_processes() + + super(LinuxNode, self).do_release() +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+
[docs] def clean_processes(self): + self.info("Cleaning up processes") + + if self.localhost: + return + + if self.get("username") != 'root': + cmd = ("sudo -S killall tcpdump || /bin/true ; " + + "sudo -S kill -9 $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; " + + "sudo -S killall -u %s || /bin/true ; " % self.get("username")) + else: + if self.state >= ResourceState.READY: + import pickle + pids = pickle.load(open("/tmp/save.proc", "rb")) + pids_temp = dict() + ps_aux = "ps aux |awk '{print $2,$11}'" + (out, err), proc = self.execute(ps_aux) + if len(out) != 0: + for line in out.strip().split("\n"): + parts = line.strip().split(" ") + pids_temp[parts[0]] = parts[1] + kill_pids = set(pids_temp.items()) - set(pids.items()) + kill_pids = ' '.join(dict(kill_pids).keys()) + + cmd = ("killall tcpdump || /bin/true ; " + + "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; " + + "kill %s || /bin/true ; " % kill_pids) + else: + cmd = ("killall tcpdump || /bin/true ; " + + "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; ") + else: + cmd = ("killall tcpdump || /bin/true ; " + + "kill $(ps aux | grep '[.]nepi' | awk '{print $2}') || /bin/true ; ") + + (out, err), proc = self.execute(cmd, retry = 1, with_lock = True) +
+
[docs] def clean_home(self): + """ Cleans all NEPI related folders in the Linux host + """ + self.info("Cleaning up home") + + cmd = "cd %s ; find . -maxdepth 1 -name \.nepi -execdir rm -rf {} + " % ( + self.home_dir ) + + return self.execute(cmd, with_lock = True) +
+
[docs] def clean_experiment(self): + """ Cleans all experiment related files in the Linux host. + It preserves NEPI files and folders that have a multi experiment + scope. + """ + self.info("Cleaning up experiment files") + + cmd = "cd %s ; find . -maxdepth 1 -name '%s' -execdir rm -rf {} + " % ( + self.exp_dir, + self.ec.exp_id ) + + return self.execute(cmd, with_lock = True) +
+
[docs] def execute(self, command, + sudo = False, + env = None, + tty = False, + forward_x11 = False, + retry = 3, + connect_timeout = 30, + strict_host_checking = False, + persistent = True, + blocking = True, + with_lock = False + ): + """ Notice that this invocation will block until the + execution finishes. If this is not the desired behavior, + use 'run' instead.""" + + if self.localhost: + (out, err), proc = execfuncs.lexec(command, + user = self.get("username"), # still problem with localhost + sudo = sudo, + 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, + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + sudo = sudo, + identity = self.get("identity"), + server_key = self.get("serverKey"), + env = env, + tty = tty, + forward_x11 = forward_x11, + retry = retry, + connect_timeout = connect_timeout, + persistent = persistent, + blocking = blocking, + strict_host_checking = strict_host_checking + ) + else: + (out, err), proc = sshfuncs.rexec( + command, + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + sudo = sudo, + identity = self.get("identity"), + server_key = self.get("serverKey"), + env = env, + tty = tty, + forward_x11 = forward_x11, + retry = retry, + connect_timeout = connect_timeout, + persistent = persistent, + blocking = blocking, + strict_host_checking = strict_host_checking + ) + + return (out, err), proc +
+
[docs] def run(self, command, home, + create_home = False, + pidfile = 'pidfile', + stdin = None, + stdout = 'stdout', + stderr = 'stderr', + sudo = False, + tty = False, + strict_host_checking = False): + + self.debug("Running command '%s'" % command) + + if self.localhost: + (out, err), proc = execfuncs.lspawn(command, pidfile, + home = home, + create_home = create_home, + 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( + command, + pidfile = pidfile, + home = home, + create_home = create_home, + 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"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + identity = self.get("identity"), + server_key = self.get("serverKey"), + tty = tty, + strict_host_checking = strict_host_checking + ) + + return (out, err), proc +
+
[docs] def getpid(self, home, pidfile = "pidfile"): + if self.localhost: + pidtuple = execfuncs.lgetpid(os.path.join(home, pidfile)) + else: + with self._node_lock: + pidtuple = sshfuncs.rgetpid( + os.path.join(home, pidfile), + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + identity = self.get("identity"), + server_key = self.get("serverKey"), + strict_host_checking = False + ) + + return pidtuple +
+
[docs] def status(self, pid, ppid): + if self.localhost: + status = execfuncs.lstatus(pid, ppid) + else: + with self._node_lock: + status = sshfuncs.rstatus( + pid, ppid, + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + identity = self.get("identity"), + server_key = self.get("serverKey"), + strict_host_checking = False + ) + + return status +
+
[docs] def kill(self, pid, ppid, sudo = False): + out = err = "" + proc = None + status = self.status(pid, ppid) + + if status == sshfuncs.ProcStatus.RUNNING: + if self.localhost: + (out, err), proc = execfuncs.lkill(pid, ppid, sudo) + else: + with self._node_lock: + (out, err), proc = sshfuncs.rkill( + pid, ppid, + host = self.get("hostname"), + user = self.get("username"), + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + sudo = sudo, + identity = self.get("identity"), + server_key = self.get("serverKey"), + strict_host_checking = False + ) + + return (out, err), proc +
+
[docs] def copy(self, src, dst): + if self.localhost: + (out, err), proc = execfuncs.lcopy(src, dst, + recursive = True) + else: + with self._node_lock: + (out, err), proc = sshfuncs.rcopy( + src, dst, + port = self.get("port"), + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + identity = self.get("identity"), + server_key = self.get("serverKey"), + recursive = True, + strict_host_checking = False) + + return (out, err), proc +
+
[docs] def upload(self, src, dst, text = False, overwrite = True, + raise_on_error = True): + """ Copy content to destination + + 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 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 + """ + # If source is a string input + f = None + if text and not os.path.isfile(src): + # src is text input that should be uploaded as file + # create a temporal file with the content to upload + f = tempfile.NamedTemporaryFile(delete=False) + f.write(src) + f.close() + src = f.name + + # If dst files should not be overwritten, check that the files do not + # 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 + + if not self.localhost: + # Build destination as <user>@<server>:<path> + dst = "%s@%s:%s" % (self.get("username"), self.get("hostname"), dst) + + ((out, err), proc) = self.copy(src, dst) + + # clean up temp file + if f: + os.remove(f.name) + + 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) +
+
[docs] 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) + + ((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) +
+
[docs] def install_packages_command(self, packages): + command = "" + if self.use_rpm: + command = rpmfuncs.install_packages_command(self.os, packages) + elif self.use_deb: + command = debfuncs.install_packages_command(self.os, packages) + else: + msg = "Error installing packages ( OS not known ) " + self.error(msg, self.os) + raise RuntimeError, msg + + return command +
+
[docs] 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. + 'run_home' is the directory from where to execute the script. + """ + command = self.install_packages_command(packages) + + run_home = run_home or home + + (out, err), proc = self.run_and_wait(command, run_home, + shfile = os.path.join(home, "instpkg.sh"), + pidfile = "instpkg_pidfile", + ecodefile = "instpkg_exitcode", + stdout = "instpkg_stdout", + stderr = "instpkg_stderr", + overwrite = False, + raise_on_error = raise_on_error) + + return (out, err), proc +
+
[docs] 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. + 'run_home' is the directory from where to execute the script. + """ + if self.use_rpm: + command = rpmfuncs.remove_packages_command(self.os, packages) + elif self.use_deb: + command = debfuncs.remove_packages_command(self.os, packages) + else: + msg = "Error removing packages ( OS not known ) " + self.error(msg) + raise RuntimeError, msg + + run_home = run_home or home + + (out, err), proc = self.run_and_wait(command, run_home, + shfile = os.path.join(home, "rmpkg.sh"), + pidfile = "rmpkg_pidfile", + ecodefile = "rmpkg_exitcode", + stdout = "rmpkg_stdout", + stderr = "rmpkg_stderr", + overwrite = False, + raise_on_error = raise_on_error) + + return (out, err), proc +
+
[docs] 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(paths) + + if isinstance(paths, str): + paths = [paths] + + cmd = " ; ".join(map(lambda path: "mkdir -p %s" % path, paths)) + + return self.execute(cmd, with_lock = True) +
+
[docs] 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) +
+
[docs] def run_and_wait(self, command, home, + shfile="cmd.sh", + env=None, + overwrite=True, + wait_run=True, + pidfile="pidfile", + ecodefile="exitcode", + stdin=None, + stdout="stdout", + stderr="stderr", + sudo=False, + tty=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 + busy-waites until the script finishes executing. + """ + + if not shfile.startswith("/"): + shfile = os.path.join(home, shfile) + + self.upload_command(command, + shfile = shfile, + ecodefile = ecodefile, + env = env, + overwrite = overwrite) + + command = "bash %s" % shfile + # run command in background in remote host + (out, err), proc = self.run(command, home, + pidfile = pidfile, + stdin = stdin, + stdout = stdout, + stderr = stderr, + sudo = sudo, + tty = tty) + + # check no errors occurred + if proc.poll(): + msg = " Failed to run command '%s' " % command + self.error(msg, out, err) + if raise_on_error: + raise RuntimeError, msg + + # Wait for pid file to be generated + pid, ppid = self.wait_pid( + home = home, + pidfile = pidfile, + raise_on_error = raise_on_error) + + if wait_run: + # wait until command finishes to execute + self.wait_run(pid, ppid) + + (eout, err), proc = self.check_errors(home, + ecodefile = ecodefile, + stderr = stderr) + + # Out is what was written in the stderr file + if err: + msg = " Failed to run command '%s' " % command + self.error(msg, eout, err) + + if raise_on_error: + raise RuntimeError, msg + + (out, oerr), proc = self.check_output(home, stdout) + + return (out, err), proc +
+
[docs] def exitcode(self, home, ecodefile = "exitcode"): + """ + Get the exit code of an application. + Returns an integer value with the exit code + """ + (out, err), proc = self.check_output(home, ecodefile) + + # Succeeded to open file, return exit code in the file + if proc.wait() == 0: + try: + return int(out.strip()) + except: + # Error in the content of the file! + return ExitCode.CORRUPTFILE + + # No such file or directory + if proc.returncode == 1: + return ExitCode.FILENOTFOUND + + # Other error from 'cat' + return ExitCode.ERROR +
+
[docs] def upload_command(self, command, + shfile="cmd.sh", + ecodefile="exitcode", + overwrite=True, + env=None): + """ Saves the command as a bash script file in the remote host, and + forces to save the exit code of the command execution to the ecodefile + """ + + if not (command.strip().endswith(";") or command.strip().endswith("&")): + command += ";" + + # The exit code of the command will be stored in ecodefile + command = " { %(command)s } ; echo $? > %(ecodefile)s ;" % { + 'command': command, + 'ecodefile': ecodefile, + } + + # Export environment + environ = self.format_environment(env) + + # Add environ to command + command = environ + command + + return self.upload(command, shfile, text=True, overwrite=overwrite) +
+
[docs] def format_environment(self, env, inline=False): + """ Formats the environment variables for a command to be executed + either as an inline command + (i.e. export PYTHONPATH=src/..; export LALAL= ..;python script.py) or + as a bash script (i.e. export PYTHONPATH=src/.. \n export LALA=.. \n) + """ + if not env: return "" + + # Remove extra white spaces + env = re.sub(r'\s+', ' ', env.strip()) + + sep = ";" if inline else "\n" + return sep.join(map(lambda e: " export %s" % e, env.split(" "))) + sep +
+
[docs] def check_errors(self, home, + ecodefile = "exitcode", + stderr = "stderr"): + """ Checks whether errors occurred while running a command. + It first checks the exit code for the command, and only if the + exit code is an error one it returns the error output. + + """ + proc = None + err = "" + + # get exit code saved in the 'exitcode' file + ecode = self.exitcode(home, ecodefile) + + if ecode in [ ExitCode.CORRUPTFILE, ExitCode.ERROR ]: + err = "Error retrieving exit code status from file %s/%s" % (home, ecodefile) + elif ecode > 0 or ecode == ExitCode.FILENOTFOUND: + # The process returned an error code or didn't exist. + # Check standard error. + (err, eerr), proc = self.check_output(home, stderr) + + # If the stderr file was not found, assume nothing bad happened, + # and just ignore the error. + # (cat returns 1 for error "No such file or directory") + if ecode == ExitCode.FILENOTFOUND and proc.poll() == 1: + err = "" + + return ("", err), proc +
+
[docs] def wait_pid(self, home, pidfile = "pidfile", raise_on_error = False): + """ Waits until the pid file for the command is generated, + and returns the pid and ppid of the process """ + pid = ppid = None + delay = 1.0 + + for i in xrange(2): + pidtuple = self.getpid(home = home, pidfile = pidfile) + + if pidtuple: + pid, ppid = pidtuple + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = " Failed to get pid for pidfile %s/%s " % ( + home, pidfile ) + self.error(msg) + + if raise_on_error: + raise RuntimeError, msg + + return pid, ppid +
+
[docs] def wait_run(self, pid, ppid, trial = 0): + """ wait for a remote process to finish execution """ + delay = 1.0 + + while True: + status = self.status(pid, ppid) + + if status is ProcStatus.FINISHED: + break + elif status is not ProcStatus.RUNNING: + delay = delay * 1.5 + time.sleep(delay) + # If it takes more than 20 seconds to start, then + # asume something went wrong + if delay > 20: + break + else: + # The app is running, just wait... + time.sleep(0.5) +
+
[docs] def check_output(self, home, filename): + """ Retrives content of file """ + (out, err), proc = self.execute("cat %s" % + os.path.join(home, filename), retry = 1, with_lock = True) + return (out, err), proc +
+
[docs] def is_alive(self): + """ Checks if host is responsive + """ + if self.localhost: + return True + + out = err = "" + msg = "Unresponsive host. Wrong answer. " + + # The underlying SSH layer will sometimes return an empty + # output (even if the command was executed without errors). + # To work arround this, repeat the operation N times or + # until the result is not empty string + try: + (out, err), proc = self.execute("echo 'ALIVE'", + blocking = True, + with_lock = True) + + if out.find("ALIVE") > -1: + return True + except: + trace = traceback.format_exc() + msg = "Unresponsive host. Error reaching host: %s " % trace + + self.error(msg, out, err) + return False +
+
[docs] def find_home(self): + """ Retrieves host home directory + """ + # The underlying SSH layer will sometimes return an empty + # output (even if the command was executed without errors). + # To work arround this, repeat the operation N times or + # until the result is not empty string + msg = "Impossible to retrieve HOME directory" + try: + (out, err), proc = self.execute("echo ${HOME}", + blocking = True, + with_lock = True) + + if out.strip() != "": + self._home_dir = out.strip() + except: + trace = traceback.format_exc() + msg = "Impossible to retrieve HOME directory %s" % trace + + if not self._home_dir: + self.error(msg) + raise RuntimeError, msg +
+
[docs] def filter_existing_files(self, src, dst): + """ Removes files that already exist in the Linux host from src list + """ + # construct a dictionary with { 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(): + command.append(" [ -f %(dst)s ] && echo '%(dst)s' " % {'dst' : d} ) + + command = ";".join(command) + + (out, err), proc = self.execute(command, retry = 1, with_lock = True) + + for d in dests.keys(): + if out.find(d) > -1: + del dests[d] + + if not dests: + return [] + + return dests.values() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/nping.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/nping.html new file mode 100644 index 00000000..e4c334ae --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/nping.html @@ -0,0 +1,312 @@ + + + + + + + + nepi.resources.linux.nping — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.nping

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxNPing(LinuxApplication): + _rtype = "linux::NPing" + + @classmethod + def _register_attributes(cls): + c = Attribute("c", + "Sets nping -c option. " + "Stop after a given number of rounds. ", + type = Types.Integer, + flags = Flags.Design) + + e = Attribute("e", + "Sets nping -e option. " + "Set the network interface to be used.", + flags = Flags.Design) + + delay = Attribute("delay", + "Sets nping --delay option. " + "Delay between probes ", + flags = Flags.Design) + + rate = Attribute("rate", + "Sets nping --rate option. " + "Send probes at a given rate ", + flags = Flags.Design) + + ttl = Attribute("ttl", + "Sets nping --ttl option. " + "Time To Live. ", + flags = Flags.Design) + + p = Attribute("p", + "Sets nping -p option. " + "Target ports. ", + type = Types.Integer, + flags = Flags.Design) + + tcp = Attribute("tcp", + "Sets nping --tcp option. " + "TCP mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + udp = Attribute("udp", + "Sets nping --udp option. " + "UDP mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + icmp = Attribute("icmp", + "Sets nping --icmp option. " + "ICMP mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + arp = Attribute("arp", + "Sets nping --arp option. " + "ARP mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + traceroute = Attribute("traceroute", + "Sets nping --traceroute option. " + "Traceroute mode. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + countinuous = Attribute("continuous", + "Run nping in a while loop", + type = Types.Bool, + default = False, + flags = Flags.Design) + + print_timestamp = Attribute("printTimestamp", + "Print timestamp before running nping", + type = Types.Bool, + default = False, + flags = Flags.Design) + + target = Attribute("target", + "nping target host (host that will be pinged)", + flags = Flags.Design) + + cls._register_attribute(c) + cls._register_attribute(e) + cls._register_attribute(delay) + cls._register_attribute(rate) + cls._register_attribute(ttl) + cls._register_attribute(p) + cls._register_attribute(tcp) + cls._register_attribute(udp) + cls._register_attribute(icmp) + cls._register_attribute(arp) + cls._register_attribute(traceroute) + cls._register_attribute(countinuous) + cls._register_attribute(print_timestamp) + cls._register_attribute(target) + + def __init__(self, ec, guid): + super(LinuxNPing, self).__init__(ec, guid) + self._home = "nping-%s" % self.guid + self._sudo_kill = True + +
[docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("install"): + self.set("install", self._install) + + if not self.get("env"): + self.set("env", "PATH=$PATH:/usr/sbin/") + + if not self.get("depends"): + self.set("depends", "nmap") + + super(LinuxNPing, self).do_deploy() +
+ @property + def _start_command(self): + args = [] + if self.get("continuous") == True: + args.append("while true; do ") + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + args.append("sudo -S nping ") + if self.get("c"): + args.append("-c %s" % self.get("c")) + if self.get("e"): + args.append("-e %s" % self.get("e")) + if self.get("delay"): + args.append("--delay %s" % self.get("delay")) + if self.get("rate"): + args.append("--rate %s" % self.get("rate")) + if self.get("ttl"): + args.append("--ttl %s" % self.get("ttl")) + if self.get("p"): + args.append("-p %s" % self.get("p")) + if self.get("tcp") == True: + args.append("--tcp") + if self.get("udp") == True: + args.append("--udp") + if self.get("icmp") == True: + args.append("--icmp") + if self.get("arp") == True: + args.append("--arp") + if self.get("traceroute") == True: + args.append("--traceroute") + + args.append(self.get("target")) + + if self.get("continuous") == True: + args.append("; done ") + + command = " ".join(args) + + return command + + @property + def _install(self): + install = "echo 'nothing to do'" + if self.node.use_rpm: + install = ( + " ( " + " ( " + " if [ `uname -m` == 'x86_64' ]; then " + " wget -O nping.rpm http://nmap.org/dist/nping-0.6.25-1.x86_64.rpm ;" + " else wget -O nping.rpm http://nmap.org/dist/nping-0.6.25-1.i386.rpm ;" + " fi " + " )" + " && sudo -S rpm -vhU nping.rpm ) ") + elif self.node.use_deb: + from nepi.resources.linux import debfuncs + install_alien = debfuncs.install_packages_command(self.node.os, "alien gcc") + install = ( + " ( " + " ( " + " if [ `uname -m` == 'x86_64' ]; then " + " wget -O nping.rpm http://nmap.org/dist/nping-0.6.25-1.x86_64.rpm ;" + " else wget -O nping.rpm http://nmap.org/dist/nping-0.6.25-1.i386.rpm ;" + " fi " + " )" + " && %s && sudo alien -i nping.rpm ) " % install_alien) + + return ("( nping --version || %s )" % install) + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccncatdceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccncatdceapplication.html new file mode 100644 index 00000000..600a4233 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccncatdceapplication.html @@ -0,0 +1,153 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
+
+@clsinit_copy
+
[docs]class LinuxNS3DceCCNCat(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCNCat" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the requested content object. ", + flags = Flags.Design) + + cls._register_attribute(content_name) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccncat") + + if self.get("contentName"): + self.set("arguments", self.get("contentName")) + + self.set("stdinFile", "") + + super(LinuxNS3DceCCNCat, self)._instantiate_object() + + @property + def _arguments(self): + args = ["-v", "add"] + + if self.get("uri"): + args.append(self.get("uri")) + if self.get("protocol"): + args.append(self.get("protocol")) + if self.get("host"): + args.append(self.get("host")) + if self.get("port"): + args.append(self.get("port")) + if self.get("ip"): + args.append(self.get("ip")) + + return ";".join(args) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccndceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccndceapplication.html new file mode 100644 index 00000000..86012dc2 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccndceapplication.html @@ -0,0 +1,198 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccndceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ccn.ns3ccndceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3ccndceapplication import NS3BaseCCNDceApplication
+
+@clsinit_copy
+
[docs]class LinuxNS3CCNDceApplication(NS3BaseCCNDceApplication): + _rtype = "linux::ns3::dce::CCNApplication" + + @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) + + cls._register_attribute(sources) + cls._register_attribute(build) + cls._register_attribute(depends) + cls._register_attribute(files) + 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 instructions to build the binary + build = self.get("build") + if build: + bcmd = self.simulation.build(build = build) + if bcmd: + command.append(bcmd) + + # Upload CCN files (e.g. repo) + files = self.get("files") + if files: + upload = [] + for file in map(str.strip, files.split(";")): + localpath, dcepath = files.split("=") + upload.append(localpath) + + sources = ";".join(upload) + fcmd = self.simulation.upload_extra_sources(sources = sources, + src_dir = self.simulation.app_home) + + if fcmd: + command.append(fcmd) + + if command: + deploy_command = ";".join(command) + prefix = "%d_deploy" % self.guid + self.simulation.execute_deploy_command(deploy_command, prefix=prefix) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnddceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnddceapplication.html new file mode 100644 index 00000000..5c91ab0f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnddceapplication.html @@ -0,0 +1,295 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccnddceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ccn.ns3ccnddceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxNS3DceCCND(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCND" + + @classmethod + def _register_attributes(cls): + debug = Attribute("debug", "Sets the CCND_DEBUG environmental variable. " + " Allowed values are : \n" + " 0 - no messages \n" + " 1 - basic messages (any non-zero value gets these) \n" + " 2 - interest messages \n" + " 4 - content messages \n" + " 8 - matching details \n" + " 16 - interest details \n" + " 32 - gory interest details \n" + " 64 - log occasional human-readable timestamps \n" + " 128 - face registration debugging \n" + " -1 - max logging \n" + " Or apply bitwise OR to these values to get combinations of them", + type = Types.Integer, + flags = Flags.Design) + + port = Attribute("port", "Sets the CCN_LOCAL_PORT environmental variable. " + "Defaults to 9695 ", + flags = Flags.Design) + + sockname = Attribute("sockname", + "Sets the CCN_LOCAL_SCOKNAME environmental variable. " + "Defaults to /tmp/.ccnd.sock", + flags = Flags.Design) + + capacity = Attribute("capacity", + "Sets the CCND_CAP environmental variable. " + "Capacity limit in terms of ContentObjects", + flags = Flags.Design) + + mtu = Attribute("mtu", "Sets the CCND_MTU environmental variable. ", + flags = Flags.Design) + + data_pause = Attribute("dataPauseMicrosec", + "Sets the CCND_DATA_PAUSE_MICROSEC environmental variable. ", + flags = Flags.Design) + + default_stale = Attribute("defaultTimeToStale", + "Sets the CCND_DEFAULT_TIME_TO_STALE environmental variable. ", + flags = Flags.Design) + + max_stale = Attribute("maxTimeToStale", + "Sets the CCND_MAX_TIME_TO_STALE environmental variable. ", + flags = Flags.Design) + + max_rte = Attribute("maxRteMicrosec", + "Sets the CCND_MAX_RTE_MICROSEC environmental variable. ", + flags = Flags.Design) + + keystore = Attribute("keyStoreDirectory", + "Sets the CCND_KEYSTORE_DIRECTORY environmental variable. ", + flags = Flags.Design) + + listen_on = Attribute("listenOn", + "Sets the CCND_LISTEN_ON environmental variable. ", + flags = Flags.Design) + + autoreg = Attribute("autoreg", + "Sets the CCND_AUTOREG environmental variable. ", + flags = Flags.Design) + + prefix = Attribute("prefix", + "Sets the CCND_PREFIX environmental variable. ", + flags = Flags.Design) + + cls._register_attribute(debug) + cls._register_attribute(port) + cls._register_attribute(sockname) + cls._register_attribute(capacity) + cls._register_attribute(mtu) + cls._register_attribute(data_pause) + cls._register_attribute(default_stale) + cls._register_attribute(max_stale) + cls._register_attribute(max_rte) + cls._register_attribute(keystore) + cls._register_attribute(listen_on) + cls._register_attribute(autoreg) + cls._register_attribute(prefix) + + @property +
[docs] def version(self): + return self._version +
+ def _instantiate_object(self): + if not self.get("depends"): + self.set("depends", self._dependencies) + + if not self.get("sources"): + self.set("sources", self._sources) + + sources = self.get("sources") + source = sources.split(" ")[0] + basename = os.path.basename(source) + self._version = ( basename.strip().replace(".tar.gz", "") + .replace(".tar","") + .replace(".gz","") + .replace(".zip","") ) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("binary"): + self.set("binary", "ccnd") + + if not self.get("environment"): + self.set("environment", self._environment) + + super(LinuxNS3DceCCND, self)._instantiate_object() + + @property + def _dependencies(self): + if self.simulation.node.use_rpm: + return ( " autoconf openssl-devel expat-devel libpcap-devel " + " ecryptfs-utils-devel libxml2-devel automake gawk " + " gcc gcc-c++ git pcre-devel make ") + elif self.simulation.node.use_deb: + return ( " autoconf libssl-dev libexpat1-dev libpcap-dev " + " libecryptfs0 libxml2-utils automake gawk gcc g++ " + " git-core pkg-config libpcre3-dev make ") + return "" + + @property + def _sources(self): + #return "http://www.ccnx.org/releases/ccnx-0.8.1.tar.gz" + return "http://www.ccnx.org/releases/ccnx-0.8.2.tar.gz" + + @property + def _build(self): + sources = self.get("sources") + source = sources.split(" ")[0] + tar = os.path.basename(source) + + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN_DCE}/ccnd && " + " echo 'binaries found, nothing to do' " + " ) || " + # If not, untar and build + " ( " + " tar zxf ${SRC}/%(tar)s && " + " cd %(version)s && " + " INSTALL_BASE=${BIN_DCE}/.. ./configure && " + " make MORE_LDLIBS='-pie -rdynamic' && " + " make install && " + " cp ${BIN_DCE}/../bin/ccn* ${BIN_DCE} && " + " cd -" + " )") % ({ 'tar': tar, + 'version': self.version + }) + + @property + def _environment(self): + envs = dict({ + "debug": "CCND_DEBUG", + "port": "CCN_LOCAL_PORT", + "sockname" : "CCN_LOCAL_SOCKNAME", + "capacity" : "CCND_CAP", + "mtu" : "CCND_MTU", + "dataPauseMicrosec" : "CCND_DATA_PAUSE_MICROSEC", + "defaultTimeToStale" : "CCND_DEFAULT_TIME_TO_STALE", + "maxTimeToStale" : "CCND_MAX_TIME_TO_STALE", + "maxRteMicrosec" : "CCND_MAX_RTE_MICROSEC", + "keyStoreDirectory" : "CCND_KEYSTORE_DIRECTORY", + "listenOn" : "CCND_LISTEN_ON", + "autoreg" : "CCND_AUTOREG", + "prefix" : "CCND_PREFIX", + }) + + env = ";".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))), + [k for k in envs.keys() if self.get(k)])) + + return env +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpeekdceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpeekdceapplication.html new file mode 100644 index 00000000..04d2773c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpeekdceapplication.html @@ -0,0 +1,136 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
+
+@clsinit_copy
+
[docs]class LinuxNS3DceCCNPeek(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCNPeek" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the requested content object. ", + flags = Flags.Design) + + cls._register_attribute(content_name) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccnpeek") + + if self.get("contentName"): + self.set("arguments", self.get("contentName")) + + self.set("stdinFile", "") + + super(LinuxNS3DceCCNPeek, self)._instantiate_object() +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpokedceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpokedceapplication.html new file mode 100644 index 00000000..76a1455c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnpokedceapplication.html @@ -0,0 +1,155 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ns3.ccn.ns3ccndceapplication \
+        import LinuxNS3CCNDceApplication
+
+import os
+import tempfile
+
+@clsinit_copy
+
[docs]class LinuxNS3DceCCNPoke(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCNPoke" + + @classmethod + def _register_attributes(cls): + content_name = Attribute("contentName", + "Content name for the requested content object. ", + flags = Flags.Design) + content = Attribute("content", + "Content to poke (as a text string). ", + flags = Flags.Design) + + cls._register_attribute(content_name) + cls._register_attribute(content) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccnpoke") + + if self.get("contentName"): + self.set("arguments", self.get("contentName")) + + # Create temporary local file to store content + content = self.get("content") + f = tempfile.NamedTemporaryFile(delete=False) + f.write(content) + f.close() + + localpath = f.name + dcepath = os.path.join("/tmp", os.path.basename(localpath)) + + self.set("environment", "HOME=/root") + self.set("files", "%s=%s" % (localpath, dcepath)) + self.set("stdinFile", dcepath) + + super(LinuxNS3DceCCNPoke, self)._instantiate_object() +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnrdceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnrdceapplication.html new file mode 100644 index 00000000..1d1f7d4b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3ccnrdceapplication.html @@ -0,0 +1,319 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 
+from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
+
+@clsinit_copy
+
[docs]class LinuxNS3DceCCNR(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::CCNR" + + @classmethod + def _register_attributes(cls): + max_fanout = Attribute("maxFanout", + "Sets the CCNR_BTREE_MAX_FANOUT environmental variable. ", + flags = Flags.Design) + + max_leaf_entries = Attribute("maxLeafEntries", + "Sets the CCNR_BTREE_MAX_LEAF_ENTRIES environmental variable. ", + flags = Flags.Design) + + max_node_bytes = Attribute("maxNodeBytes", + "Sets the CCNR_BTREE_MAX_NODE_BYTES environmental variable. ", + flags = Flags.Design) + + max_node_pool = Attribute("maxNodePool", + "Sets the CCNR_BTREE_MAX_NODE_POOL environmental variable. ", + flags = Flags.Design) + + content_cache = Attribute("contentCache", + "Sets the CCNR_CONTENT_CACHE environmental variable. ", + flags = Flags.Design) + + debug = Attribute("debug", + "Sets the CCNR_DEBUG environmental variable. " + "Logging level for ccnr. Defaults to WARNING.", + type = Types.Enumerate, + allowed = [ + "NONE", + "SEVERE", + "ERROR", + "WARNING", + "INFO", + "FINE, FINER, FINEST"], + flags = Flags.Design) + + directory = Attribute("directory", + "Sets the CCNR_DIRECTORY environmental variable. ", + flags = Flags.Design) + + global_prefix = Attribute("globalPrefix", + "Sets the CCNR_GLOBAL_PREFIX environmental variable. ", + flags = Flags.Design) + + listen_on = Attribute("listenOn", + "Sets the CCNR_LISTEN_ON environmental variable. ", + flags = Flags.Design) + + min_send_bufsize = Attribute("minSendBufsize", + "Sets the CCNR_MIN_SEND_BUFSIZE environmental variable. ", + flags = Flags.Design) + + proto = Attribute("proto", + "Sets the CCNR_PROTO environmental variable. ", + flags = Flags.Design) + + status_port = Attribute("statusPort", + "Sets the CCNR_STATUS_PORT environmental variable. ", + flags = Flags.Design) + + start_write_scope_limit = Attribute("startWriteScopeLimit", + "Sets the CCNR_START_WRITE_SCOPE_LIMIT environmental variable. ", + flags = Flags.Design) + + ccns_debug = Attribute("ccnsDebug", + "Sets the CCNS_DEBUG environmental variable. ", + flags = Flags.Design) + + ccns_enable = Attribute("ccnsEnable", + "Sets the CCNS_ENABLE environmental variable. ", + flags = Flags.Design) + + ccns_faux_error = Attribute("ccnsFauxError", + "Sets the CCNS_FAUX_ERROR environmental variable. ", + flags = Flags.Design) + + ccns_heartbeat_micros = Attribute("ccnsHeartBeatMicros", + "Sets the CCNS_HEART_BEAT_MICROS environmental variable. ", + flags = Flags.Design) + + ccns_max_compares_busy = Attribute("ccnsMaxComparesBusy", + "Sets the CCNS_MAX_COMPARES_BUSY environmental variable. ", + flags = Flags.Design) + + ccns_max_fetch_busy = Attribute("ccnsMaxFetchBusy", + "Sets the CCNS_MAX_FETCH_BUSY environmental variable. ", + flags = Flags.Design) + + ccns_node_fetch_lifetime = Attribute("ccnsNodeFetchLifetime", + "Sets the CCNS_NODE_FETCH_LIFETIME environmental variable. ", + flags = Flags.Design) + + ccns_note_err = Attribute("ccnsNoteErr", + "Sets the CCNS_NOTE_ERR environmental variable. ", + flags = Flags.Design) + + ccns_repo_store = Attribute("ccnsRepoStore", + "Sets the CCNS_REPO_STORE environmental variable. ", + flags = Flags.Design) + + ccns_root_advise_fresh = Attribute("ccnsRootAdviseFresh", + "Sets the CCNS_ROOT_ADVISE_FRESH environmental variable. ", + flags = Flags.Design) + + ccns_root_advise_lifetime = Attribute("ccnsRootAdviseLifetime", + "Sets the CCNS_ROOT_ADVISE_LIFETIME environmental variable. ", + flags = Flags.Design) + + ccns_stable_enabled = Attribute("ccnsStableEnabled", + "Sets the CCNS_STABLE_ENABLED environmental variable. ", + flags = Flags.Design) + + ccns_sync_scope = Attribute("ccnsSyncScope", + "Sets the CCNS_SYNC_SCOPE environmental variable. ", + flags = Flags.Design) + + repo_file = Attribute("repoFile1", + "The Repository uses $CCNR_DIRECTORY/repoFile1 for " + "persistent storage of CCN Content Objects", + flags = Flags.Design) + + cls._register_attribute(max_fanout) + cls._register_attribute(max_leaf_entries) + cls._register_attribute(max_node_bytes) + cls._register_attribute(max_node_pool) + cls._register_attribute(content_cache) + cls._register_attribute(debug) + cls._register_attribute(directory) + cls._register_attribute(global_prefix) + cls._register_attribute(listen_on) + cls._register_attribute(min_send_bufsize) + cls._register_attribute(proto) + cls._register_attribute(status_port) + cls._register_attribute(start_write_scope_limit) + cls._register_attribute(ccns_debug) + cls._register_attribute(ccns_enable) + cls._register_attribute(ccns_faux_error) + cls._register_attribute(ccns_heartbeat_micros) + cls._register_attribute(ccns_max_compares_busy) + cls._register_attribute(ccns_max_fetch_busy) + cls._register_attribute(ccns_node_fetch_lifetime) + cls._register_attribute(ccns_note_err) + cls._register_attribute(ccns_repo_store) + cls._register_attribute(ccns_root_advise_fresh) + cls._register_attribute(ccns_root_advise_lifetime) + cls._register_attribute(ccns_stable_enabled) + cls._register_attribute(ccns_sync_scope) + cls._register_attribute(repo_file) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccnr") + + if not self.get("environment"): + self.set("environment", self._environment) + + repoFile1 = self.get("repoFile1") + if repoFile1: + env = "CCNR_DIRECTORY=/REPO/" + environment = self.get("environment") + if environment: + env += ";" + environment + self.set("environment", env) + self.set("files", "%s=/REPO/repoFile1" % repoFile1) + + super(LinuxNS3DceCCNR, self)._instantiate_object() + + @property + def _environment(self): + envs = dict({ + "maxFanout": "CCNR_BTREE_MAX_FANOUT", + "maxLeafEntries": "CCNR_BTREE_MAX_LEAF_ENTRIES", + "maxNodeBytes": "CCNR_BTREE_MAX_NODE_BYTES", + "maxNodePool": "CCNR_BTREE_MAX_NODE_POOL", + "contentCache": "CCNR_CONTENT_CACHE", + "debug": "CCNR_DEBUG", + "directory": "CCNR_DIRECTORY", + "globalPrefix": "CCNR_GLOBAL_PREFIX", + "listenOn": "CCNR_LISTEN_ON", + "minSendBufsize": "CCNR_MIN_SEND_BUFSIZE", + "proto": "CCNR_PROTO", + "statusPort": "CCNR_STATUS_PORT", + "startWriteScopeLimit": "CCNR_START_WRITE_SCOPE_LIMIT", + "ccnsDebug": "CCNS_DEBUG", + "ccnsEnable": "CCNS_ENABLE", + "ccnsFauxError": "CCNS_FAUX_ERROR", + "ccnsHeartBeatMicros": "CCNS_HEART_BEAT_MICROS", + "ccnsMaxComparesBusy": "CCNS_MAX_COMPARES_BUSY", + "ccnsMaxFetchBusy": "CCNS_MAX_FETCH_BUSY", + "ccnsNodeFetchLifetime": "CCNS_NODE_FETCH_LIFETIME", + "ccnsNoteErr": "CCNS_NOTE_ERR", + "ccnsRepoStore": "CCNS_REPO_STORE", + "ccnsRootAdviseFresh": "CCNS_ROOT_ADVISE_FRESH", + "ccnsRootAdviseLifetime": "CCNS_ROOT_ADVISE_LIFETIME", + "ccnsStableEnabled": "CCNS_STABLE_ENABLED", + "ccnsSyncScope": "CCNS_SYNC_SCOPE", + }) + + env = ";".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))), + [k for k in envs.keys() if self.get(k)])) + + return env +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3fibentrydceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3fibentrydceapplication.html new file mode 100644 index 00000000..b9cea6f5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ccn/ns3fibentrydceapplication.html @@ -0,0 +1,196 @@ + + + + + + + + nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ns3.ccn.ns3ccndceapplication import LinuxNS3CCNDceApplication
+
+@clsinit_copy
+
[docs]class LinuxNS3DceFIBEntry(LinuxNS3CCNDceApplication): + _rtype = "linux::ns3::dce::FIBEntry" + + @classmethod + def _register_attributes(cls): + uri = Attribute("uri", + "URI prefix to match and route for this FIB entry", + default = "ccnx:/", + flags = Flags.Design) + + protocol = Attribute("protocol", + "Transport protocol used in network connection to peer " + "for this FIB entry. One of 'udp' or 'tcp'.", + type = Types.Enumerate, + default = "udp", + allowed = ["udp", "tcp"], + flags = Flags.Design) + + host = Attribute("host", + "Peer hostname used in network connection for this FIB entry. ", + flags = Flags.Design) + + port = Attribute("port", + "Peer port address used in network connection to peer " + "for this FIB entry.", + flags = Flags.Design) + + ip = Attribute("ip", + "Peer host public IP used in network connection for this FIB entry. ", + flags = Flags.Design) + + home = Attribute("home", "Sets HOME environmental variable. ", + default = "/root", + flags = Flags.Design) + + cls._register_attribute(uri) + cls._register_attribute(protocol) + cls._register_attribute(host) + cls._register_attribute(port) + cls._register_attribute(ip) + cls._register_attribute(home) + + def _instantiate_object(self): + if not self.get("binary"): + self.set("binary", "ccndc") + + if not self.get("arguments"): + self.set("arguments", self._arguments) + + if not self.get("environment"): + self.set("environment", self._environment) + + super(LinuxNS3DceFIBEntry, self)._instantiate_object() + + @property + def _environment(self): + envs = dict({ + "home": "HOME", + }) + + env = ";".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))), + [k for k in envs.keys() if self.get(k)])) + + return env + + @property + def _arguments(self): + args = ["-v", "add"] + + if self.get("uri"): + args.append(self.get("uri")) + if self.get("protocol"): + args.append(self.get("protocol")) + if self.get("host"): + args.append(self.get("host")) + if self.get("port"): + args.append(self.get("port")) + if self.get("ip"): + args.append(self.get("ip")) + + return ";".join(args) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/fdudptunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/fdudptunnel.html new file mode 100644 index 00000000..bbe45c4d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/fdudptunnel.html @@ -0,0 +1,473 @@ + + + + + + + + nepi.resources.linux.ns3.fdudptunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.fdudptunnel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.udptunnel import LinuxUdpTunnel
+from nepi.util.sshfuncs import ProcStatus
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import base64
+import os
+import socket
+import time
+
+@clsinit_copy
+
[docs]class LinuxNs3FdUdpTunnel(LinuxUdpTunnel): + _rtype = "linux::ns3::FdUdpTunnel" + _help = "Constructs a tunnel between two Ns-3 FdNetdevices " \ + "located in remote Linux nodes using a UDP connection " + _platform = "linux::ns3" + + @classmethod + def _register_attributes(cls): + cipher = Attribute("cipher", + "Cipher to encript communication. " + "One of PLAIN, AES, Blowfish, DES, DES3. ", + default = None, + allowed = ["PLAIN", "AES", "Blowfish", "DES", "DES3"], + type = Types.Enumerate, + 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.Design) + + txqueuelen = Attribute("txQueueLen", + "Specifies the interface's transmission queue length. " + "Defaults to 1000. ", + type = Types.Integer, + flags = Flags.Design) + + bwlimit = Attribute("bwLimit", + "Specifies the interface's emulated bandwidth in bytes " + "per second.", + type = Types.Integer, + flags = Flags.Design) + + cls._register_attribute(cipher) + cls._register_attribute(cipher_key) + cls._register_attribute(txqueuelen) + cls._register_attribute(bwlimit) + + def __init__(self, ec, guid): + super(LinuxUdpTunnel, self).__init__(ec, guid) + self._home = "fd-udp-tunnel-%s" % self.guid + self._pids = dict() + self._fd1 = None + self._fd1node = None + self._fd2 = None + self._fd2node = None + self._pi = False + +
[docs] def log_message(self, msg): + self.get_endpoints() + return " guid %d - %s - %s - %s " % (self.guid, + self.node1.get("hostname"), + self.node2.get("hostname"), + msg) +
+
[docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + if not self._fd2 or not self._fd1: + from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice + devices = self.get_connected(NS3BaseFdNetDevice.get_rtype()) + if not devices or len(devices) != 2: + msg = "linux::ns3::TunTapFdLink must be connected to exactly one FdNetDevice" + self.error(msg) + raise RuntimeError, msg + + self._fd1 = devices[0] + self._fd2 = devices[1] + + simu = self._fd1.simulation + from nepi.resources.linux.node import LinuxNode + nodes = simu.get_connected(LinuxNode.get_rtype()) + self._fd1node = nodes[0] + + simu = self._fd2.simulation + from nepi.resources.linux.node import LinuxNode + nodes = simu.get_connected(LinuxNode.get_rtype()) + self._fd2node = nodes[0] + + if self._fd1node.get("hostname") == \ + self._fd2node.get("hostname"): + msg = "linux::ns3::FdUdpTunnel requires endpoints on different hosts" + self.error(msg) + raise RuntimeError, msg + + return [self._fd1, self._fd2] +
+ @property +
[docs] def pi(self): + return self._pi +
+ @property +
[docs] def endpoint1(self): + return self._fd1 +
+ @property +
[docs] def endpoint2(self): + return self._fd2 +
+ @property +
[docs] def node1(self): + return self._fd1node +
+ @property +
[docs] def node2(self): + return self._fd2node +
+
[docs] def endpoint_node(self, endpoint): + node = None + if endpoint == self.endpoint1: + node = self.node1 + else: + node = self.node2 + + return node +
+
[docs] def app_home(self, endpoint): + node = self.endpoint_node(endpoint) + return os.path.join(node.exp_home, self._home) +
+
[docs] def run_home(self, endpoint): + return os.path.join(self.app_home(endpoint), self.ec.run_id) +
+
[docs] def upload_sources(self, endpoint): + scripts = [] + + # vif-passfd python script + linux_passfd = os.path.join(os.path.dirname(__file__), + "..", + "scripts", + "fd-udp-connect.py") + + scripts.append(linux_passfd) + + # tunnel creation python script + tunchannel = os.path.join(os.path.dirname(__file__), + "..", + "scripts", + "tunchannel.py") + + scripts.append(tunchannel) + + # Upload scripts + scripts = ";".join(scripts) + + node = self.endpoint_node(endpoint) + node.upload(scripts, + os.path.join(node.src_dir), + overwrite = False) +
+
[docs] def endpoint_mkdir(self, endpoint): + node = self.endpoint_node(endpoint) + run_home = self.run_home(endpoint) + node.mkdir(run_home) +
+
[docs] def initiate_connection(self, endpoint, remote_endpoint): + cipher = self.get("cipher") + cipher_key = self.get("cipherKey") + bwlimit = self.get("bwLimit") + txqueuelen = self.get("txQueueLen") + + # Upload the tunnel creating script + self.upload_sources(endpoint) + + # Request an address to send the file descriptor to the ns-3 simulation + address = endpoint.recv_fd() + + # execute the tunnel creation script + node = self.endpoint_node(remote_endpoint) + port = self.initiate(endpoint, remote_endpoint, address, cipher, + cipher_key, bwlimit, txqueuelen) + + return port +
+
[docs] def establish_connection(self, endpoint, remote_endpoint, port): + self.establish(endpoint, remote_endpoint, port) +
+
[docs] def verify_connection(self, endpoint, remote_endpoint): + self.verify(endpoint) +
+
[docs] def terminate_connection(self, endpoint, remote_endpoint): + # Nothing to do + return +
+
[docs] def check_state_connection(self): + # Make sure the process is still running in background + # No execution errors occurred. Make sure the background + # process with the recorded pid is still running. + + node1 = self.endpoint_node(self.endpoint1) + node2 = self.endpoint_node(self.endpoint2) + run_home1 = self.run_home(self.endpoint1) + run_home2 = self.run_home(self.endpoint1) + (pid1, ppid1) = self._pids[endpoint1] + (pid2, ppid2) = self._pids[endpoint2] + + status1 = node1.status(pid1, ppid1) + status2 = node2.status(pid2, ppid2) + + if status1 == ProcStatus.FINISHED and \ + status2 == ProcStatus.FINISHED: + + # check if execution errors occurred + (out1, err1), proc1 = node1.check_errors(run_home1) + (out2, err2), proc2 = node2.check_errors(run_home2) + + if err1 or err2: + msg = "Error occurred in tunnel" + self.error(msg, err1, err2) + self.fail() + else: + self.set_stopped() +
+
[docs] def wait_local_port(self, endpoint): + """ Waits until the local_port file for the endpoint is generated, + and returns the port number + + """ + return self.wait_file(endpoint, "local_port") +
+
[docs] def wait_result(self, endpoint): + """ Waits until the return code file for the endpoint is generated + + """ + return self.wait_file(endpoint, "ret_file") +
+
[docs] def wait_file(self, endpoint, filename): + """ Waits until file on endpoint is generated """ + result = None + delay = 1.0 + + node = self.endpoint_node(endpoint) + run_home = self.run_home(endpoint) + + for i in xrange(20): + (out, err), proc = node.check_output(run_home, filename) + + if out: + result = out.strip() + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = "Couldn't retrieve %s" % filename + self.error(msg, out, err) + raise RuntimeError, msg + + return result +
+
[docs] def initiate(self, endpoint, remote_endpoint, address, cipher, cipher_key, + bwlimit, txqueuelen): + + command = self._initiate_command(endpoint, remote_endpoint, + address, cipher, cipher_key, bwlimit, txqueuelen) + + node = self.endpoint_node(endpoint) + run_home = self.run_home(endpoint) + app_home = self.app_home(endpoint) + + # upload command to connect.sh script + shfile = os.path.join(app_home, "fd-udp-connect.sh") + node.upload_command(command, + shfile = shfile, + overwrite = False) + + # invoke connect script + cmd = "bash %s" % shfile + (out, err), proc = node.run(cmd, run_home) + + # check if execution errors occurred + msg = "Failed to connect endpoints " + + if proc.poll(): + self.error(msg, out, err) + raise RuntimeError, msg + + # Wait for pid file to be generated + pid, ppid = node.wait_pid(run_home) + + self._pids[endpoint] = (pid, ppid) + + # Check for error information on the remote machine + (out, err), proc = node.check_errors(run_home) + # Out is what was written in the stderr file + if err: + msg = " Failed to start command '%s' " % command + self.error(msg, out, err) + raise RuntimeError, msg + + port = self.wait_local_port(endpoint) + + return port +
+ def _initiate_command(self, endpoint, remote_endpoint, address, + cipher, cipher_key, bwlimit, txqueuelen): + local_node = self.endpoint_node(endpoint) + local_run_home = self.run_home(endpoint) + local_app_home = self.app_home(endpoint) + remote_node = self.endpoint_node(remote_endpoint) + + local_ip = local_node.get("ip") + remote_ip = remote_node.get("ip") + + local_port_file = os.path.join(local_run_home, "local_port") + remote_port_file = os.path.join(local_run_home, "remote_port") + ret_file = os.path.join(local_run_home, "ret_file") + + address = base64.b64encode(address) + + command = [""] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/fd-udp-connect.py") + command.append("-a %s" % address) + command.append("-p %s" % local_port_file) + command.append("-P %s" % remote_port_file) + command.append("-o %s" % local_ip) + command.append("-O %s" % remote_ip) + command.append("-R %s" % ret_file) + command.append("-t %s" % "IFF_TAP") + if self.pi: + command.append("-n") + if cipher: + command.append("-c %s" % cipher) + if cipher_key: + command.append("-k %s " % cipher_key) + if txqueuelen: + command.append("-q %s " % txqueuelen) + if bwlimit: + command.append("-b %s " % bwlimit) + + command = " ".join(command) + command = self.replace_paths(command, node=local_node, + app_home=local_app_home, run_home=local_run_home) + + return command + +
[docs] def establish(self, endpoint, remote_endpoint, port): + node = self.endpoint_node(endpoint) + run_home = self.run_home(endpoint) + + # upload remote port number to file + remote_port = "%s\n" % port + node.upload(remote_port, + os.path.join(run_home, "remote_port"), + text = True, + overwrite = False) +
+
[docs] def verify(self, endpoint): + self.wait_result(endpoint) +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3client.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3client.html new file mode 100644 index 00000000..af81026d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3client.html @@ -0,0 +1,208 @@ + + + + + + + + nepi.resources.linux.ns3.ns3client — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ns3client

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+import threading
+
+from optparse import OptionParser, SUPPRESS_HELP
+
+from nepi.resources.ns3.ns3client import NS3Client
+from nepi.resources.ns3.ns3server import NS3WrapperMessage
+
+
[docs]class LinuxNS3Client(NS3Client): + def __init__(self, simulation): + super(LinuxNS3Client, self).__init__() + self._simulation = weakref.ref(simulation) + self._socket_lock = threading.Lock() + + @property +
[docs] def simulation(self): + return self._simulation() +
+
[docs] 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)) + + with self._socket_lock: + 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, + with_lock = True) + + if (err and proc.poll()) or reply.strip() == "": + msg = (" Couldn't connect to remote socket %s - REPLY: %s " + "- ERROR: %s ") % ( + self.simulation.remote_socket, reply, err) + self.simulation.error(msg, reply, err) + raise RuntimeError(msg) + + reply = cPickle.loads(base64.b64decode(reply)) + + return reply +
+
[docs] def create(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.CREATE, *args, **kwargs) +
+
[docs] def factory(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.FACTORY, *args, **kwargs) +
+
[docs] def invoke(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.INVOKE, *args, **kwargs) +
+
[docs] def set(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.SET, *args, **kwargs) +
+
[docs] def get(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.GET, *args, **kwargs) +
+
[docs] def flush(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.FLUSH, *args, **kwargs) +
+
[docs] def start(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.START, *args, **kwargs) +
+
[docs] def stop(self, *args, **kwargs): + return self.send_msg(NS3WrapperMessage.STOP, *args, **kwargs) +
+
[docs] def shutdown(self, *args, **kwargs): + try: + return self.send_msg(NS3WrapperMessage.SHUTDOWN, *args, **kwargs) + except: + pass + + return None +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3dceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3dceapplication.html new file mode 100644 index 00000000..b5c8d333 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3dceapplication.html @@ -0,0 +1,170 @@ + + + + + + + + nepi.resources.linux.ns3.ns3dceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ns3dceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication
+
+@clsinit_copy
+
[docs]class LinuxNS3DceApplication(NS3BaseDceApplication): + _rtype = "linux::ns3::dce::Application" + + @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) + + cls._register_attribute(sources) + cls._register_attribute(build) + cls._register_attribute(depends) + + 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 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3pingdceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3pingdceapplication.html new file mode 100644 index 00000000..d4d6d766 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3pingdceapplication.html @@ -0,0 +1,345 @@ + + + + + + + + nepi.resources.linux.ns3.ns3pingdceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ns3pingdceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ns3.ns3dceapplication import LinuxNS3DceApplication
+
+@clsinit_copy
+
[docs]class LinuxDcePing(LinuxNS3DceApplication): + _rtype = "linux::ns3::dce::Ping" + + @classmethod + def _register_attributes(cls): + count = Attribute("count", + "Sets ping -c option. Determines the number of ECHO_REQUEST " + "packates to send before stopping.", + type = Types.Integer, + flags = Flags.Design) + + mark = Attribute("mark", + "Sets ping -m option. Uses 'mark' to tag outgoing packets. ", + flags = Flags.Design) + + interval = Attribute("interval", + "Sets ping -i option. Leaves interval seconds between " + "successive ECHO_REUQEST packets. ", + flags = Flags.Design) + + address = Attribute("address", + "Sets ping -I option. Sets ECHO_REQUEST packets souce address " + "to the specified interface address ", + flags = Flags.Design) + + preload = Attribute("preload", + "Sets ping -l option. Sends preload amount of packets " + "without waiting for a reply ", + 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.Design) + + pattern = Attribute("pattern", + "Sets ping -p option. Species a up to 16 ''pad'' bytes to fill " + "out sent packets. ", + 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.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.Design) + + quiet = Attribute("quiet", + "Sets ping -q option. Disables ping standard output ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + rec_route = Attribute("recordRoute", + "Sets ping -R option. Includes the RECORD_ROUTE option in the " + "ECHO REQUEST packet and displays route buffer on the Disables " + "ping standard output.", + type = Types.Bool, + default = False, + 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.Design) + + packetsize = Attribute("packetSize", + "Sets ping -s option. Specifies the number of data bytes to be " + "sent. Defaults to 56. ", + flags = Flags.Design) + + sendbuff = Attribute("sendBuff", + "Sets ping -S option. Specifies the number of packets to buffer. " + "Defaults to one. ", + flags = Flags.Design) + + ttl = Attribute("ttl", + "Sets ping -t option. Specifies the IP Time to Live for the " + "packets. ", + flags = Flags.Design) + + timestamp = Attribute("timestamp", + "Sets ping -T option. Sets special IP timestamp options. ", + flags = Flags.Design) + + hint = Attribute("hint", + "Sets ping -M option. Selects Path MTU Discovery strategy. ", + flags = Flags.Design) + + full_latency = Attribute("fullLatency", + "Sets ping -U option. Calculates round trip time taking into " + "account the full user-to-user latency instead of only the " + "network round trip time. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + verbose = Attribute("verbose", + "Sets ping -v option. Verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + flood = Attribute("flood", + "Sets ping -f option. Flood ping. ", + type = Types.Bool, + default = False, + 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.Design) + + timeout = Attribute("timeout", + "Sets ping -W option. Time to wait for a respone in seconds .", + flags = Flags.Design) + + target = Attribute("target", + "The host to ping .", + flags = Flags.Design) + + cls._register_attribute(count) + cls._register_attribute(mark) + cls._register_attribute(interval) + cls._register_attribute(address) + cls._register_attribute(preload) + cls._register_attribute(numeric) + cls._register_attribute(pattern) + cls._register_attribute(printtmp) + cls._register_attribute(tos) + cls._register_attribute(quiet) + cls._register_attribute(rec_route) + cls._register_attribute(route_bypass) + cls._register_attribute(packetsize) + cls._register_attribute(sendbuff) + cls._register_attribute(ttl) + cls._register_attribute(timestamp) + cls._register_attribute(hint) + cls._register_attribute(full_latency) + cls._register_attribute(verbose) + cls._register_attribute(flood) + cls._register_attribute(deadline) + cls._register_attribute(timeout) + cls._register_attribute(target) + + def _instantiate_object(self): + self.set("sources", self._sources) + self.set("build", self._build) + self.set("binary", "ping") + self.set("arguments", self._arguments) + + super(LinuxDcePing, self)._instantiate_object() + + @property + def _sources(self): + return "http://www.skbuff.net/iputils/iputils-s20101006.tar.bz2" + + @property + def _build(self): + return (" ( " + " test -f ${BIN_DCE}/ping && " + " echo 'binaries found, nothing to do' " + " ) || ( " + "tar xvjf ${SRC}/iputils-s20101006.tar.bz2 && " + "cd iputils-s20101006/ && " + "sed -i 's/CFLAGS=/CFLAGS+=/g' Makefile && " + "make CFLAGS=-fPIC LDFLAGS='-pie -rdynamic' ping && " + "cp ping ${BIN_DCE} && cd - " + " )" + ) + + @property + def _arguments(self): + args = [] + + if self.get("count"): + args.append("-c %s" % self.get("count")) + if self.get("mark"): + args.append("-m %s" % self.get("mark")) + if self.get("interval"): + args.append("-i %s" % self.get("interval")) + if self.get("address"): + args.append("-I %s" % self.get("address")) + if self.get("preload"): + args.append("-l %s" % self.get("preload")) + if self.get("numeric") == True: + args.append("-n") + if self.get("pattern"): + args.append("-p %s" % self.get("pattern")) + if self.get("tos"): + args.append("-Q %s" % self.get("tos")) + if self.get("quiet"): + args.append("-q %s" % self.get("quiet")) + if self.get("recordRoute") == True: + args.append("-R") + if self.get("routeBypass") == True: + args.append("-r") + if self.get("packetSize"): + args.append("-s %s" % self.get("packetSize")) + if self.get("sendBuff"): + args.append("-S %s" % self.get("sendBuff")) + if self.get("ttl"): + args.append("-t %s" % self.get("ttl")) + if self.get("timestamp"): + args.append("-T %s" % self.get("timestamp")) + if self.get("hint"): + args.append("-M %s" % self.get("hint")) + if self.get("fullLatency") == True: + args.append("-U") + if self.get("verbose") == True: + args.append("-v") + if self.get("flood") == True: + args.append("-f") + if self.get("deadline"): + args.append("-w %s" % self.get("deadline")) + if self.get("timeout"): + args.append("-W %s" % self.get("timeout")) + args.append(self.get("target")) + + return ";".join(args) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3simulation.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3simulation.html new file mode 100644 index 00000000..a7ecfa5c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/ns3simulation.html @@ -0,0 +1,827 @@ + + + + + + + + nepi.resources.linux.ns3.ns3simulation — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.ns3simulation

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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, ResourceFactory
+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
+
[docs]class LinuxNS3Simulation(LinuxApplication, NS3Simulation): + _rtype = "linux::ns3::Simulation" + + @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) + + enable_dump = Attribute("enableDump", + "Enable dumping the remote executed ns-3 commands to a script " + "in order to later reproduce and debug the experiment", + type = Types.Bool, + default = False, + 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.20", + #default = "ns-3-dev", + flags = Flags.Design) + + pybindgen_version = Attribute("pybindgenVersion", + "Version of pybindgen to install from bazar repo", + default = "868", + #default = "876", + flags = Flags.Design) + + dce_version = Attribute("dceVersion", + "Version of dce to install from nsam repo (tag branch for repo)", + #default = "dce-1.3", + default = "dce-dev", + flags = Flags.Design) + + populate_routing_tables = Attribute("populateRoutingTables", + "Invokes Ipv4GlobalRoutingHelper.PopulateRoutingTables() ", + default = False, + type = Types.Bool, + flags = Flags.Design) + + stoptime = Attribute("StopTime", + "Time at which the simulation will stop", + 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(enable_dump) + cls._register_attribute(verbose) + cls._register_attribute(build_mode) + cls._register_attribute(ns3_version) + cls._register_attribute(pybindgen_version) + cls._register_attribute(dce_version) + cls._register_attribute(populate_routing_tables) + cls._register_attribute(stoptime) + + 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._enable_dce = None + self._dce_helper = None + + @property +
[docs] def socket_name(self): + return self._socket_name +
+ @property +
[docs] def remote_socket(self): + return os.path.join(self.run_home, self.socket_name) +
+
[docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + # stout needs to get flushed on the ns-3 server side, else we will + # get an empty stream. We try twice to retrieve the stream + # if we get empty stdout since the stream might not be + # flushed immediately. + if name.endswith("stdout"): + self._client.flush() + result = LinuxApplication.trace(self, name, attr, block, offset) + if result: + return result + # Let the stream be flushed + time.sleep(1) + + return LinuxApplication.trace(self, name, attr, block, offset) +
+
[docs] 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 wrapper debug python script + ns3_wrapper_debug = os.path.join(os.path.dirname(__file__), "..", "..", "ns3", + "ns3wrapper_debug.py") + + self.node.upload(ns3_wrapper_debug, + os.path.join(self.node.src_dir, "ns3wrapper", "ns3wrapper_debug.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) +
+
[docs] def upload_extra_sources(self, sources = None, src_dir = None): + return super(LinuxNS3Simulation, self).upload_sources( + sources = sources, + src_dir = src_dir) +
+
[docs] 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() + + # Wait until the remote socket is created + self.wait_remote_socket() +
+
[docs] 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) +
+
[docs] 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(self.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() +
+
[docs] 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") + + time = self.get("StopTime") + if time: + self._client.stop(time=time) + + self._client.start() + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_stop(self): + """ Stops simulation execution + + """ + if self.state == ResourceState.STARTED: + if not self.get("StopTime"): + self._client.stop() + self.set_stopped() +
+
[docs] 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 +
[docs] def state(self): + super(LinuxApplication, self).state + + if self._state == ResourceState.STARTED: + try: + is_finished = self.invoke(SIMULATOR_UUID, "isFinished") + + if is_finished: + self.set_stopped() + except: + msg = "Simulator failed. Can not retrieve state" + out = "" + + import traceback + err = traceback.format_exc() + self.error(msg, out, err) + self.do_fail() + + return self._state +
+ @property +
[docs] def enable_dce(self): + if self._enable_dce is None: + from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication + rclass = ResourceFactory.get_resource_type( + NS3BaseDceApplication.get_rtype()) + + self._enable_dce = False + for guid in self.ec.resources: + rm = self.ec.get_resource(guid) + if isinstance(rm, rclass): + self._enable_dce = True + + from nepi.resources.ns3.ns3dcehelper import NS3DceHelper + self._dce_helper = NS3DceHelper(self) + break + + return self._enable_dce +
+ @property +
[docs] def dce_helper(self): + return self._dce_helper +
+ @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("enableDump"): + command.append("-D") + + 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 +
[docs] def ns3_repo(self): + return "http://code.nsnam.org" +
+ @property +
[docs] def pygccxml_version(self): + return "pygccxml-1.0.0" +
+ @property +
[docs] def dce_repo(self): + return "http://code.nsnam.org/ns-3-dce" + #eturn "http://code.nsnam.org/epmancini/ns-3-dce" +
+ @property +
[docs] def dce_version(self): + dce_version = self.get("dceVersion") + return dce_version or "dce-dev" +
+ @property +
[docs] def ns3_build_location(self): + location = "${BIN}/ns-3/%(ns3_version)s%(dce_version)s/%(build_mode)s/build" \ + % { + "ns3_version": self.get("ns3Version"), + "dce_version": "-%s" % self.get("dceVersion") \ + if self.enable_dce else "", + "build_mode": self.get("buildMode"), + } + + return location + +
+ @property +
[docs] def ns3_src_location(self): + location = "${SRC}/ns-3/%(ns3_version)s" \ + % { + "ns3_version": self.get("ns3Version"), + } + + return location +
+ @property +
[docs] def dce_src_location(self): + location = "${SRC}/ns-3-dce/%(dce_version)s" \ + % { + "dce_version": self.get("dceVersion"), + } + + return location +
+ @property + def _clone_ns3_command(self): + source = self.get("sources") + + if not source: + clone_ns3_cmd = "hg clone %(ns3_repo)s/%(ns3_version)s %(ns3_src)s" \ + % { + "ns3_version": self.get("ns3Version"), + "ns3_repo": self.ns3_repo, + "ns3_src": self.ns3_src_location, + } + else: + if source.find(".tar.gz") > -1: + clone_ns3_cmd = ( + "tar xzf ${SRC}/ns-3/%(basename)s " + " --strip-components=1 -C %(ns3_src)s" + ) % { + "basename": os.path.basename(source), + "ns3_src": self.ns3_src_location, + } + elif source.find(".tar") > -1: + clone_ns3_cmd = ( + "tar xf ${SRC}/ns-3/%(basename)s " + " --strip-components=1 -C %(ns3_src)s" + ) % { + "basename": os.path.basename(source), + "ns3_src": self.ns3_src_location, + } + elif source.find(".zip") > -1: + basename = os.path.basename(source) + bare_basename = basename.replace(".zip", "") + + clone_ns3_cmd = ( + "unzip ${SRC}/ns-3/%(basename)s && " + "mv ${SRC}/ns-3/%(bare_basename)s %(ns3_src)s" + ) % { + "bare_basename": basename_name, + "basename": basename, + "ns3_src": self.ns3_src_location, + } + + return clone_ns3_cmd + + @property + def _clone_dce_command(self): + clone_dce_cmd = " echo 'DCE will not be built' " + + if self.enable_dce: + dce_version = self.dce_version + dce_tag = "" + if dce_version != "dce-dev": + dce_tag = "-r %s" % dce_version + + clone_dce_cmd = ( + # DCE installation + # Test if dce is alredy cloned + " ( " + " ( " + " ( test -d %(dce_src)s ) " + " && echo 'dce binaries found, nothing to do'" + " ) " + " ) " + " || " + # Get dce source code + " ( " + " mkdir -p %(dce_src)s && " + " hg clone %(dce_repo)s %(dce_tag)s %(dce_src)s" + " ) " + ) % { + "dce_repo": self.dce_repo, + "dce_tag": dce_tag, + "dce_src": self.dce_src_location, + } + + return clone_dce_cmd + + @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. + clone_ns3_cmd = self._clone_ns3_command + clone_dce_cmd = self._clone_dce_command + + ns3_build_cmd = ( + # NS3 installation + "( " + " ( " + # Test if ns-3 is alredy cloned + " ((( test -d %(ns3_src)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 %(ns3_src)s && " + " %(clone_ns3_cmd)s " + " ) " + " ) " + ") " + " && " + "( " + " %(clone_dce_cmd)s " + ") " + ) % { + "ns3_src": self.ns3_src_location, + "pybindgen_version": self.get("pybindgenVersion"), + "pygccxml_version": self.pygccxml_version, + "clone_ns3_cmd": clone_ns3_cmd, + "clone_dce_cmd": clone_dce_cmd, + } + + return ns3_build_cmd + + @property + def _install_dce_command(self): + install_dce_cmd = " echo 'DCE will not be installed'" + + if self.enable_dce: + install_dce_cmd = ( + " ( " + " ((test -d %(ns3_build)s/bin_dce ) && " + " echo 'dce binaries found, nothing to do' )" + " ) " + " ||" + " ( " + # If not, copy build to dce + " cd %(dce_src)s && " + " rm -rf %(dce_src)s/build && " + " ./waf configure %(enable_opt)s --with-pybindgen=${SRC}/pybindgen/%(pybindgen_version)s " + " --prefix=%(ns3_build)s --with-ns3=%(ns3_build)s && " + " ./waf build && " + " ./waf install && " + " [ ! -e %(ns3_build)s/lib/python/site-packages/ns/dce.so ] && " + " mv %(ns3_build)s/lib*/python*/site-packages/ns/dce.so %(ns3_build)s/lib/python/site-packages/ns/ " + " )" + ) % { + "pybindgen_version": self.get("pybindgenVersion"), + "enable_opt": "--enable-opt" if self.get("buildMode") == "optimized" else "", + "ns3_build": self.ns3_build_location, + "dce_src": self.dce_src_location, + } + + return install_dce_cmd + + @property + def _install(self): + install_dce_cmd = self._install_dce_command + + install_ns3_cmd = ( + # Test if ns-3 is alredy installed + "(" + " ( " + " ( ( (test -d %(ns3_build)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)s && " + " cd %(ns3_src)s && " + " rm -rf %(ns3_src)s/build && " + " ./waf configure -d %(build_mode)s --with-pybindgen=${SRC}/pybindgen/%(pybindgen_version)s " + " --prefix=%(ns3_build)s && " + " ./waf build && " + " ./waf install && " + " mv %(ns3_build)s/lib*/python* %(ns3_build)s/lib/python " + " )" + ") " + " && " + "( " + " %(install_dce_cmd)s " + ") " + ) % { + "pybindgen_version": self.get("pybindgenVersion"), + "build_mode": self.get("buildMode"), + "install_dce_cmd": install_dce_cmd, + "ns3_build": self.ns3_build_location, + "ns3_src": self.ns3_src_location, + } + + return install_ns3_cmd + + @property + def _environment(self): + env = [] + env.append("PYTHONPATH=$PYTHONPATH:${NS3BINDINGS:=%(ns3_build)s/lib/python/site-packages}" % { + "ns3_build": self.ns3_build_location + }) + # 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)s/lib}" % { + "ns3_build": self.ns3_build_location + }) + env.append("DCE_PATH=$NS3LIBRARIES/../bin_dce") + env.append("DCE_ROOT=$NS3LIBRARIES/..") + + return " ".join(env) + +
[docs] 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_location) + ) +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+
[docs] def wait_remote_socket(self): + """ Waits until the remote socket is created + """ + command = " [ -e %s ] && echo 'DONE' " % self.remote_socket + + for i in xrange(200): + (out, err), proc = self.node.execute(command, retry = 1, + with_lock = True) + + if out.find("DONE") > -1: + break + else: + raise RuntimeError("Remote socket not found at %s" % \ + self.remote_socket) + +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/tuntapfdlink.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/tuntapfdlink.html new file mode 100644 index 00000000..7ca4fe91 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ns3/tuntapfdlink.html @@ -0,0 +1,251 @@ + + + + + + + + nepi.resources.linux.ns3.tuntapfdlink — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ns3.tuntapfdlink

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 ResourceState, clsinit_copy
+from nepi.resources.linux.application import LinuxApplication
+
+import base64
+import fcntl
+import os
+import socket
+import struct
+
+@clsinit_copy
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/ping.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ping.html new file mode 100644 index 00000000..e019c1eb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/ping.html @@ -0,0 +1,372 @@ + + + + + + + + nepi.resources.linux.ping — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.ping

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 
+from nepi.resources.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxPing(LinuxApplication): + _rtype = "linux::Ping" + + @classmethod + def _register_attributes(cls): + count = Attribute("count", + "Sets ping -c option. Determines the number of ECHO_REQUEST " + "packates to send before stopping.", + type = Types.Integer, + flags = Flags.Design) + + mark = Attribute("mark", + "Sets ping -m option. Uses 'mark' to tag outgoing packets. ", + flags = Flags.Design) + + interval = Attribute("interval", + "Sets ping -i option. Leaves interval seconds between " + "successive ECHO_REUQEST packets. ", + flags = Flags.Design) + + address = Attribute("address", + "Sets ping -I option. Sets ECHO_REQUEST packets souce address " + "to the specified interface address ", + flags = Flags.Design) + + preload = Attribute("preload", + "Sets ping -l option. Sends preload amount of packets " + "without waiting for a reply ", + 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.Design) + + pattern = Attribute("pattern", + "Sets ping -p option. Species a up to 16 ''pad'' bytes to fill " + "out sent packets. ", + 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.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.Design) + + quiet = Attribute("quiet", + "Sets ping -q option. Disables ping standard output ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + rec_route = Attribute("recordRoute", + "Sets ping -R option. Includes the RECORD_ROUTE option in the " + "ECHO REQUEST packet and displays route buffer on the Disables " + "ping standard output.", + type = Types.Bool, + default = False, + 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.Design) + + packetsize = Attribute("packetSize", + "Sets ping -s option. Specifies the number of data bytes to be " + "sent. Defaults to 56. ", + flags = Flags.Design) + + sendbuff = Attribute("sendBuff", + "Sets ping -S option. Specifies the number of packets to buffer. " + "Defaults to one. ", + flags = Flags.Design) + + ttl = Attribute("ttl", + "Sets ping -t option. Specifies the IP Time to Live for the " + "packets. ", + flags = Flags.Design) + + timestamp = Attribute("timestamp", + "Sets ping -T option. Sets special IP timestamp options. ", + flags = Flags.Design) + + hint = Attribute("hint", + "Sets ping -M option. Selects Path MTU Discovery strategy. ", + flags = Flags.Design) + + full_latency = Attribute("fullLatency", + "Sets ping -U option. Calculates round trip time taking into " + "account the full user-to-user latency instead of only the " + "network round trip time. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + verbose = Attribute("verbose", + "Sets ping -v option. Verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + flood = Attribute("flood", + "Sets ping -f option. Flood ping. ", + type = Types.Bool, + default = False, + 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.Design) + + timeout = Attribute("timeout", + "Sets ping -W option. Time to wait for a respone in seconds .", + flags = Flags.Design) + + target = Attribute("target", + "The host to ping .", + flags = Flags.Design) + + early_start = Attribute("earlyStart", + "Start ping as early as deployment. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(count) + cls._register_attribute(mark) + cls._register_attribute(interval) + cls._register_attribute(address) + cls._register_attribute(preload) + cls._register_attribute(numeric) + cls._register_attribute(pattern) + cls._register_attribute(printtmp) + cls._register_attribute(tos) + cls._register_attribute(quiet) + cls._register_attribute(rec_route) + cls._register_attribute(route_bypass) + cls._register_attribute(packetsize) + cls._register_attribute(sendbuff) + cls._register_attribute(ttl) + cls._register_attribute(timestamp) + cls._register_attribute(hint) + cls._register_attribute(full_latency) + cls._register_attribute(verbose) + cls._register_attribute(flood) + cls._register_attribute(deadline) + cls._register_attribute(timeout) + cls._register_attribute(target) + cls._register_attribute(early_start) + + def __init__(self, ec, guid): + super(LinuxPing, self).__init__(ec, guid) + self._home = "ping-%s" % self.guid + +
[docs] def upload_start_command(self): + super(LinuxPing, self).upload_start_command() + + if self.get("earlyStart") == True: + self._run_in_background() +
+
[docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + super(LinuxPing, self).do_deploy() +
+
[docs] def do_start(self): + if self.get("earlyStart") == True: + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg + else: + super(LinuxPing, self).do_start() +
+ @property + def _start_command(self): + args = [] + + args.append("echo 'Starting PING to %s' ;" % self.get("target")) + + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + + args.append("ping ") + + if self.get("count"): + args.append("-c %s" % self.get("count")) + if self.get("mark"): + args.append("-m %s" % self.get("mark")) + if self.get("interval"): + args.append("-i %s" % self.get("interval")) + if self.get("address"): + args.append("-I %s" % self.get("address")) + if self.get("preload"): + args.append("-l %s" % self.get("preload")) + if self.get("numeric") == True: + args.append("-n") + if self.get("pattern"): + args.append("-p %s" % self.get("pattern")) + if self.get("tos"): + args.append("-Q %s" % self.get("tos")) + if self.get("quiet"): + args.append("-q %s" % self.get("quiet")) + if self.get("recordRoute") == True: + args.append("-R") + if self.get("routeBypass") == True: + args.append("-r") + if self.get("packetSize"): + args.append("-s %s" % self.get("packetSize")) + if self.get("sendBuff"): + args.append("-S %s" % self.get("sendBuff")) + if self.get("ttl"): + args.append("-t %s" % self.get("ttl")) + if self.get("timestamp"): + args.append("-T %s" % self.get("timestamp")) + if self.get("hint"): + args.append("-M %s" % self.get("hint")) + if self.get("fullLatency") == True: + args.append("-U") + if self.get("verbose") == True: + args.append("-v") + if self.get("flood") == True: + args.append("-f") + if self.get("deadline"): + args.append("-w %s" % self.get("deadline")) + if self.get("timeout"): + args.append("-W %s" % self.get("timeout")) + args.append(self.get("target")) + + command = " ".join(args) + + return command + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/route.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/route.html new file mode 100644 index 00000000..a55f75f9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/route.html @@ -0,0 +1,251 @@ + + + + + + + + nepi.resources.linux.route — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.route

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.application import LinuxApplication
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxRoute(LinuxApplication): + _rtype = "linux::Route" + _help = "Adds a route to the host using iptools " + + @classmethod + def _register_attributes(cls): + network = Attribute("network", "Network address", flags=Flags.Design) + prefix = Attribute("prefix", "IP prefix length", flags=Flags.Design) + nexthop = Attribute("nexthop", "Nexthop IP", flags=Flags.Design) + + cls._register_attribute(network) + cls._register_attribute(prefix) + cls._register_attribute(nexthop) + + def __init__(self, ec, guid): + super(LinuxRoute, self).__init__(ec, guid) + self._home = "route-%s" % self.guid + self._device = None + + @property +
[docs] def device(self): + if not self._device: + from nepi.resources.linux.tap import LinuxTap + from nepi.resources.linux.tun import LinuxTun + from nepi.resources.linux.interface import LinuxInterface + tap = self.get_connected(LinuxTap.get_rtype()) + tun = self.get_connected(LinuxTun.get_rtype()) + interface = self.get_connected(LinuxInterface.get_rtype()) + if tap: self._device = tap[0] + elif tun: self._device = tun[0] + elif interface: self._device = interface[0] + else: + raise RuntimeError, "linux::Routes must be connected to a "\ + "linux::TAP, linux::TUN, or linux::Interface" + return self._device +
+ @property +
[docs] def node(self): + return self.device.node +
+
[docs] def upload_start_command(self): + # We want to make sure the route is configured + # before the deploy is over, so we execute the + # start script now and wait until it finishes. + command = self.get("command") + command = self.replace_paths(command) + + shfile = os.path.join(self.app_home, "start.sh") + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = True) +
+
[docs] def upload_sources(self): + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + + self.node.upload(stop_command, + os.path.join(self.app_home, "stop.sh"), + text = True, + # Overwrite file every time. + # The stop.sh has the path to the socket, which should change + # on every experiment run. + overwrite = True) +
+
[docs] def do_deploy(self): + if not self.device or self.device.state < ResourceState.PROVISIONED: + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_stop(self): + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % command) + + command = "bash %s" % os.path.join(self.app_home, "stop.sh") + (out, err), proc = self.execute_command(command, + blocking = True) + + if err: + msg = " Failed to stop command '%s' " % command + self.error(msg, out, err) + + self.set_stopped() +
+ @property + def _start_command(self): + network = self.get("network") + prefix = self.get("prefix") + nexthop = self.get("nexthop") + devicename = self.device.get("deviceName") + + command = [] + command.append("sudo -S ip route add %s/%s %s dev %s" % ( + self.get("network"), + self.get("prefix"), + "default" if not nexthop else "via %s" % nexthop, + devicename)) + + return " ".join(command) + + @property + def _stop_command(self): + network = self.get("network") + prefix = self.get("prefix") + nexthop = self.get("nexthop") + devicename = self.device.get("deviceName") + + command = [] + command.append("sudo -S ip route del %s/%s %s dev %s" % ( + self.get("network"), + self.get("prefix"), + "default" if not nexthop else "via %s" % nexthop, + devicename)) + + return " ".join(command) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/rpmfuncs.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/rpmfuncs.html new file mode 100644 index 00000000..4503d568 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/rpmfuncs.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.linux.rpmfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.rpmfuncs

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+RPM_FUSION_URL = 'http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm'
+RPM_FUSION_URL_F12 = 'http://download1.rpmfusion.org/free/fedora/releases/12/Everything/x86_64/os/rpmfusion-free-release-12-1.noarch.rpm'
+RPM_FUSION_URL_F14 = 'http://download1.rpmfusion.org/free/fedora/releases/14/Everything/x86_64/os/rpmfusion-free-release-14-0.4.noarch.rpm'
+
+
+# TODO: Investigate using http://nixos.org/nix/
+
+
[docs]def install_packages_command(os, packages): + if not isinstance(packages, list): + packages = [packages] + + cmd = install_rpmfusion_command(os) + if cmd: cmd += " ; " + cmd += " && ".join(map(lambda p: + " { rpm -q %(package)s || sudo -S yum -y install --nogpgcheck %(package)s ; } " % { + 'package': p}, packages)) + + #cmd = { rpm -q rpmfusion-free-release || sudo -s rpm -i ... ; } && { rpm -q vim || sudo yum -y install vim ; } && .. + return cmd +
+
[docs]def remove_packages_command(os, packages): + if not isinstance(packages, list): + packages = [packages] + + cmd = " && ".join(map(lambda p: + " { rpm -q %(package)s && sudo -S yum -y remove %(package)s ; } " % { + 'package': p}, packages)) + + #cmd = { rpm -q vim && sudo yum -y remove vim ; } && .. + return cmd +
+
[docs]def install_rpmfusion_command(os): + from nepi.resources.linux.node import OSType + + cmd = " { rpm -q rpmfusion-free-release || sudo -S rpm -i %(package)s ; } " + + if (os & OSType.FEDORA_8): + # RpmFusion for Fedora 8 is unmaintained + cmd = "" + elif (os & OSType.FEDORA_12): + # For f12 + cmd = cmd % {'package': RPM_FUSION_URL_F12} + elif (os & OSType.FEDORA_14): + # For f14 + cmd = cmd % {'package': RPM_FUSION_URL_F14} + else: + # For f14+ + cmd = cmd % {'package': RPM_FUSION_URL} + + return cmd +
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/tap.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tap.html new file mode 100644 index 00000000..a49c3306 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tap.html @@ -0,0 +1,710 @@ + + + + + + + + nepi.resources.linux.tap — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.tap

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.application import LinuxApplication
+from nepi.resources.linux.node import LinuxNode
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+import time
+
+PYTHON_VSYS_VERSION = "1.0"
+
+@clsinit_copy
+
[docs]class LinuxTap(LinuxApplication): + _rtype = "linux::Tap" + _help = "Creates a TAP device on a Linux host" + + IFF_TUN = 0x0001 + IFF_TAP = 0x0002 + + @classmethod + def _register_attributes(cls): + ip = Attribute("ip", "IPv4 Address", + flags = Flags.Design) + + mac = Attribute("mac", "MAC Address", + flags = Flags.Design) + + prefix = Attribute("prefix", "IPv4 network prefix", + 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.NoWrite) + + up = Attribute("up", "Link up", default=True, + type = Types.Bool) + + pointopoint = Attribute("pointopoint", "Peer IP address", + flags = Flags.Design) + + txqueuelen = Attribute("txqueuelen", "Length of transmission queue", + flags = Flags.Design) + + txqueuelen = Attribute("txqueuelen", "Length of transmission queue", + flags = Flags.Design) + + gre_key = Attribute("greKey", + "GRE key to be used to configure GRE tunnel", + default = "1", + flags = Flags.Design) + + gre_remote = Attribute("greRemote", + "Public IP of remote endpoint for GRE tunnel", + flags = Flags.Design) + + pi = Attribute("pi", "Add PI (protocol information) header", + default = False, + type = Types.Bool) + + tear_down = Attribute("tearDown", + "Bash script to be executed before releasing the resource", + flags = Flags.Design) + + cls._register_attribute(ip) + cls._register_attribute(mac) + cls._register_attribute(prefix) + cls._register_attribute(mtu) + cls._register_attribute(devname) + cls._register_attribute(up) + cls._register_attribute(pointopoint) + cls._register_attribute(txqueuelen) + cls._register_attribute(gre_key) + cls._register_attribute(gre_remote) + cls._register_attribute(pi) + cls._register_attribute(tear_down) + + def __init__(self, ec, guid): + super(LinuxTap, self).__init__(ec, guid) + self._gre_enabled = None + self._vif_prefix = "tap" + self._vif_type = "IFF_TAP" + self._vif_type_flag = LinuxTap.IFF_TAP + self._home = "%s-%s" % (self.vif_prefix, self.guid) + + @property +
[docs] def node(self): + node = self.get_connected(LinuxNode.get_rtype()) + if node: return node[0] + raise RuntimeError, "linux::TAP/TUN devices must be connected to a linux::Node" +
+ @property +
[docs] def gre_enabled(self): + if self._gre_enabled is None: + from nepi.resources.linux.gretunnel import LinuxGRETunnel + gre = self.get_connected(LinuxGRETunnel.get_rtype()) + if gre: self._gre_enabled = True + + return self._gre_enabled +
+
[docs] def upload_sources(self): + scripts = [] + + # udp-connect python script + udp_connect = os.path.join(os.path.dirname(__file__), "scripts", + "linux-udp-connect.py") + + scripts.append(udp_connect) + + tap_create = os.path.join(os.path.dirname(__file__), "scripts", + "linux-tap-create.py") + + scripts.append(tap_create) + + tap_delete = os.path.join(os.path.dirname(__file__), "scripts", + "linux-tap-delete.py") + + scripts.append(tap_delete) + + # tunnel creation python script + tunchannel = os.path.join(os.path.dirname(__file__), "scripts", + "tunchannel.py") + + scripts.append(tunchannel) + + # Upload scripts + scripts = ";".join(scripts) + + self.node.upload(scripts, + os.path.join(self.node.src_dir), + overwrite = False) + + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + + self.node.upload(stop_command, + os.path.join(self.app_home, "stop.sh"), + text = True, + # Overwrite file every time. + # The stop.sh has the path to the socket, which should change + # on every experiment run. + overwrite = True) +
+ def upload_start_command(self): + # If GRE mode is enabled, TAP creation is delayed until the + # tunnel is established + if not self.gre_enabled: + # We want to make sure the device is up and running + # before the deploy is over, so we execute the + # start script now and wait until it finishes. + command = self.get("command") + command = self.replace_paths(command) + + shfile = os.path.join(self.app_home, "start.sh") + self.node.run_and_wait(command, self.run_home, + shfile = shfile, + overwrite = True) + +
[docs] def upload_start_command(self): + # If GRE mode is enabled, TAP creation is delayed until the + # tunnel is established + if not self.gre_enabled: + # Overwrite file every time. + # The start.sh has the path to the socket, wich should change + # on every experiment run. + command = self.get("command") + + self.info("Uploading command '%s'" % command) + + # replace application specific paths in the command + command = self.replace_paths(command) + + # replace application specific paths in the environment + env = self.get("env") + env = env and self.replace_paths(env) + + shfile = os.path.join(self.app_home, "start.sh") + + self.node.upload_command(command, + shfile = shfile, + env = env, + overwrite = True) + + # We want to make sure the device is up and running + # before the deploy finishes, so we execute now the + # start script. We run it in background, because the + # TAP will live for as long as the process that + # created it is running, and wait until the TAP + # is created. + self._run_in_background() +
+
[docs] def do_deploy(self): + if not self.node or self.node.state < ResourceState.PROVISIONED: + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if self.gre_enabled: + self._vif_prefix = "gre" + self._home = "%s-%s" % (self.vif_prefix, self.guid) + + if not self.get("deviceName"): + self.set("deviceName", "%s%d" % (self.vif_prefix, self.guid)) + + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("depends"): + self.set("depends", self._dependencies) + + if not self.get("install"): + self.set("install", self._install) + + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_stop(self): + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % command) + + command = "bash %s" % os.path.join(self.app_home, "stop.sh") + (out, err), proc = self.execute_command(command, + blocking = True) + + if err: + msg = " Failed to stop command '%s' " % command + self.error(msg, out, err) + + self.set_stopped() +
+ @property +
[docs] def state(self): + state_check_delay = 0.5 + if self._state == ResourceState.STARTED and \ + tdiffsec(tnow(), self._last_state_check) > state_check_delay: + + if self.get("deviceName"): + (out, err), proc = self.node.execute("ifconfig") + + if out.strip().find(self.get("deviceName")) == -1: + # tap is not running is not running (socket not found) + self.set_stopped() + + self._last_state_check = tnow() + + return self._state +
+
[docs] def do_release(self): + # Node needs to wait until all associated RMs are released + # to be released + from nepi.resources.linux.tunnel import LinuxTunnel + rms = self.get_connected(LinuxTunnel.get_rtype()) + + for rm in rms: + if rm.state < ResourceState.STOPPED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + super(LinuxTap, self).do_release() +
+
[docs] def gre_connect(self, remote_endpoint, connection_app_home, + connection_run_home): + gre_connect_command = self._gre_connect_command(remote_endpoint, + connection_app_home, connection_run_home) + + # upload command to connect.sh script + shfile = os.path.join(connection_app_home, "gre-connect.sh") + self.node.upload_command(gre_connect_command, + shfile = shfile, + overwrite = False) + + # invoke connect script + cmd = "bash %s" % shfile + (out, err), proc = self.node.run(cmd, connection_run_home, + pidfile = "gre_connect_pidfile", + stdout = "gre_connect_stdout", + stderr = "gre_connect_stderr", + ) + + # check if execution errors occurred + msg = " Failed to connect endpoints " + + if proc.poll() or err: + self.error(msg, out, err) + raise RuntimeError, msg + + # Wait for pid file to be generated + pid, ppid = self.node.wait_pid(connection_run_home, + pidfile = "gre_connect_pidfile") + + # If the process is not running, check for error information + # on the remote machine + if not pid or not ppid: + (out, err), proc = self.node.check_errors(connection_run_home, + stderr = "gre_connect_stderr") + + # Out is what was written in the stderr file + if err: + msg = " Failed to start command '%s' " % command + self.error(msg, out, err) + raise RuntimeError, msg + + return True +
+
[docs] def initiate_udp_connection(self, remote_endpoint, connection_app_home, + connection_run_home, cipher, cipher_key, bwlimit, txqueuelen): + port = self.udp_connect(remote_endpoint, connection_app_home, + connection_run_home, cipher, cipher_key, bwlimit, txqueuelen) + return port +
+
[docs] def udp_connect(self, remote_endpoint, connection_app_home, + connection_run_home, cipher, cipher_key, bwlimit, txqueuelen): + udp_connect_command = self._udp_connect_command( + remote_endpoint, connection_app_home, connection_run_home, + cipher, cipher_key, bwlimit, txqueuelen) + + # upload command to connect.sh script + shfile = os.path.join(connection_app_home, "udp-connect.sh") + self.node.upload_command(udp_connect_command, + shfile = shfile, + overwrite = False) + + # invoke connect script + cmd = "bash %s" % shfile + (out, err), proc = self.node.run(cmd, connection_run_home, + pidfile = "udp_connect_pidfile", + stdout = "udp_connect_stdout", + stderr = "udp_connect_stderr", + ) + + # check if execution errors occurred + msg = "Failed to connect endpoints " + + if proc.poll(): + self.error(msg, out, err) + raise RuntimeError, msg + + # Wait for pid file to be generated + self._pid, self._ppid = self.node.wait_pid( + connection_run_home, + pidfile = "udp_connect_pidfile") + + # If the process is not running, check for error information + # on the remote machine + if not self._pid or not self._ppid: + (out, err), proc = self.node.check_errors( + connection_run_home, + stderr = "udp_connect_stderr") + + # Out is what was written in the stderr file + if err: + msg = " Failed to start command '%s' " % command + self.error(msg, out, err) + raise RuntimeError, msg + + return self.wait_file(connection_run_home, "local_port") +
+
[docs] def establish_udp_connection(self, remote_endpoint, + connection_app_home, connection_run_home, port): + # upload remote port number to file + rem_port = "%s\n" % port + self.node.upload(rem_port, + os.path.join(connection_run_home, "remote_port"), + text = True, + overwrite = False) +
+
[docs] def verify_connection(self, remote_endpoint, + connection_app_home, connection_run_home): + + return self.wait_file(connection_run_home, "ret_file") +
+
[docs] def terminate_connection(self, remote_endpoint, + connection_app_home, connection_run_home): + if self._pid and self._ppid: + (out, err), proc = self.node.kill(self._pid, self._ppid, + sudo = True) + + # check if execution errors occurred + if proc.poll() and err: + msg = " Failed to Kill the Tap" + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def check_status(self): + return self.node.status(self._pid, self._ppid) +
+
[docs] def wait_file(self, home, filename): + """ Waits until file on endpoint is generated """ + result = None + delay = 1.0 + + for i in xrange(20): + (out, err), proc = self.node.check_output(home, filename) + if out: + result = out.strip() + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = "Couldn't retrieve %s" % filename + self.error(msg, out, err) + raise RuntimeError, msg + + return result +
+ @property + def _start_command(self): + if self.gre_enabled: + command = [] + else: + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/linux-tap-create.py") + command.append("-t %s" % self.vif_type) + command.append("-a %s" % self.get("ip")) + command.append("-n %s" % self.get("prefix")) + command.append("-N %s " % self.get("deviceName")) + command.append("-S %s " % self.sock_name) + if self.get("pi"): + command.append("-p") + + return " ".join(command) + + @property + def _stop_command(self): + if self.gre_enabled: + command = self._stop_gre_command + else: + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/linux-tap-delete.py") + command.append("-N %s " % self.get("deviceName")) + command.append("-S %s " % self.sock_name) + command = " ".join(command) + + return command + + def _gre_connect_command(self, remote_endpoint, + connection_app_home, connecrion_app_home): + # Set the remote endpoint to (private) device IP + self.set("pointopoint", remote_endpoint.get("ip")) + ## public node IP + self.set("greRemote", remote_endpoint.node.get("ip")) + + # Generate GRE connect command + command = ["("] + command.append(self._stop_gre_command) + command.append(") ; (") + command.append(self._start_gre_command) + command.append(")") + + command = " ".join(command) + command = self.replace_paths(command) + + return command + + @property + def _start_gre_command(self): + command = [] + command.append("sudo -S modprobe ip_gre") + command.append("sudo -S ip tunnel add %s mode gre remote %s local %s ttl 255 csum key %s" % ( + self.get("deviceName"), + self.get("greRemote"), + self.node.get("ip"), + self.get("greKey") + )) + command.append("sudo -S ip addr add %s/%s peer %s/%s dev %s" % ( + self.get("ip"), + self.get("prefix"), + self.get("pointopoint"), + self.get("prefix"), + self.get("deviceName"), + )) + command.append("sudo -S ip link set %s up " % self.get("deviceName")) + + return ";".join(command) + + @property + def _stop_gre_command(self): + command = [] + command.append("sudo -S modprobe -r ip_gre") + command.append("sudo -S ip link set down dev %s" % ( + self.get("deviceName"), + )) + command.append("sudo -S ip link del dev %s" % ( + self.get("deviceName"), + )) + + return ";".join(command) + + def _udp_connect_command(self, remote_endpoint, + connection_app_home, connection_run_home, + cipher, cipher_key, bwlimit, txqueuelen): + + # Set the remote endpoint to the IP of the device + self.set("pointopoint", remote_endpoint.get("ip")) + + # Public IP of the remote NODE to stablish tunnel + remote_ip = remote_endpoint.node.get("ip") + local_ip = self.node.get("ip") + + local_port_file = os.path.join(connection_run_home, + "local_port") + + remote_port_file = os.path.join(connection_run_home, + "remote_port") + + ret_file = os.path.join(connection_run_home, + "ret_file") + + # Generate UDP connect command + # Use the start command to configure TAP with peer info + start_command = self._start_command + + command = [""] + # Use pl-vid-udp-connect.py to stablish the tunnel between endpoints + command.append("sudo -S") + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/linux-udp-connect.py") + command.append("-t %s" % self.vif_type) + command.append("-S %s " % self.sock_name) + command.append("-p %s " % local_port_file) + command.append("-P %s " % remote_port_file) + command.append("-o %s " % local_ip) + command.append("-O %s " % remote_ip) + command.append("-R %s " % ret_file) + if self.get("pi"): + command.append("-n") + if cipher: + command.append("-c %s " % cipher) + if cipher_key: + command.append("-k %s " % cipher_key) + if txqueuelen: + command.append("-q %s " % txqueuelen) + if bwlimit: + command.append("-b %s " % bwlimit) + + command = " ".join(command) + command = self.replace_paths(command) + + return command + + @property + def _dependencies(self): + return "mercurial make gcc" + + @property + def _install(self): + # Install python-vsys and python-passfd + install_passfd = ( " ( python -c 'import passfd' ) " + " || " + " ( " + " cd ${SRC} ; " + " hg clone http://nepi.inria.fr/code/python-passfd ; " + " cd python-passfd ; " + " make all ; " + " sudo -S make install " + " )" ) + + return install_passfd + + def valid_connection(self, guid): + # TODO: Validate! + return True + + @property +
[docs] def vif_type(self): + return self._vif_type +
+ @property +
[docs] def vif_type_flag(self): + return self._vif_type_flag +
+ @property +
[docs] def vif_prefix(self): + return self._vif_prefix +
+ @property +
[docs] def sock_name(self): + return os.path.join(self.run_home, "%s.sock" % self.vif_prefix) +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/tcpdump.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tcpdump.html new file mode 100644 index 00000000..690d4808 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tcpdump.html @@ -0,0 +1,499 @@ + + + + + + + + nepi.resources.linux.tcpdump — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.tcpdump

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxTcpdump(LinuxApplication): + _rtype = "linux::Tcpdump" + + @classmethod + def _register_attributes(cls): + A = Attribute("A", + "Sets tcpdump -A option. " + "Prints each packet (minus its link level header) in ASCII.", + type = Types.Bool, + default = False, + 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.Design) + + B = Attribute("B", + "Sets tcpdump -B option. " + "Sets the operaing system capture buffer size in untils of " + "KiB (1024 bytes).", + flags = Flags.Design) + + c = Attribute("c", + "Sets tcpdump -c option. " + "Exists after receiving count packets.", + flags = Flags.Design) + + C = Attribute("C", + "Sets tcpdump -C option. " + "Before writing a raw packet to a savefile, check whether the " + "file is currently larger than file_size and, if so, close the " + "current savefile and open a new one. " + "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.Design) + + d = Attribute("d", + "Sets tcpdump -d option. " + "Dump the compiled packet-matching code in a human readable form " + "to standard output and stop.", + type = Types.Bool, + default = False, + 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.Design) + + ddd = Attribute("ddd", + "Sets tcpdump -ddd option. " + "Dump packet-matching code as decimal numbers " + "(preceded with a count).", + type = Types.Bool, + default = False, + flags = Flags.Design) + + D = Attribute("D", + "Sets tcpdump -D option. " + "Print the list of the network interfaces available on the system " + "and on which tcpdump can capture packets. ", + type = Types.Bool, + default = False, + 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.Design) + + F = Attribute("F", + "Sets tcpdump -F option. " + "Use file as input for the filter expression.", + flags = Flags.Design) + + G = Attribute("G", + "Sets tcpdump -G option. " + "If specified, rotates the dump file specified with the -w " + "option every rotate_seconds seconds. ", + type = Types.Bool, + default = False, + 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.Design) + + I = Attribute("I", + "Sets tcpdump -I option. " + "Put the interface in 'monitor mode'; this is supported only " + "on IEEE 802.11 Wi-Fi interfaces, and supported only on some " + "operating systems. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + j = Attribute("j", + "Sets tcpdump -j option. " + "Sets the time stamp type for the capture to tstamp_type. " + "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.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.Design) + + l = Attribute("l", + "Sets tcpdump -l option. " + "Make stdout line buffered. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + U = Attribute("U", + "Sets tcpdump -U option. " + "Similar to -l in its behavior, but it will cause output to be " + "``packet-buffered'', so that the output is written to stdout " + "at the end of each packet. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + n = Attribute("n", + "Sets tcpdump -n option. " + "Don't convert addresses (i.e., host addresses, port numbers, " + "etc.) to names.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + N = Attribute("N", + "Sets tcpdump -N option. " + "Don't print domain name qualification of host names. " + "E.g., if you give this flag then tcpdump will print ``nic'' " + "instead of ``nic.ddn.mil''.", + type = Types.Bool, + default = False, + 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.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.Design) + + T = Attribute("T", + "Sets tcpdump -T option. " + "Force packets selected by 'expression' to be interpreted the " + "specified type. Currently known types are aodv (Ad-hoc " + "On-demand Distance Vector protocol), cnfp (Cisco NetFlow " + "protocol), rpc (Remote Procedure Call), rtp (Real-Time " + "Applications protocol), rtcp (Real-Time Applications control " + "protocol), snmp (Simple Network Management Protocol), tftp " + "(Trivial File Transfer Protocol), vat (Visual Audio Tool), " + "and wb (distributed White Board).", + 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.Design) + + tt = Attribute("tt", + "Sets tcpdump -tt option. " + "Print an unformatted timestamp on each dump line. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + ttt = Attribute("ttt", + "Sets tcpdump -ttt option. " + "Print a delta (micro-second resolution) between current " + "and previous line on each dump line.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + tttt = Attribute("tttt", + "Sets tcpdump -tttt option. " + "Print a timestamp in default format proceeded by date on " + "each dump line. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + ttttt = Attribute("ttttt", + "Sets tcpdump -ttttt option. " + "Print a delta (micro-second resolution) between current and " + "first line on each dump line.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + v = Attribute("v", + "Sets tcpdump -v option. " + "When parsing and printing, produce (slightly more) " + "verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + vv = Attribute("vv", + "Sets tcpdump -vv option. " + "Even more verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + vvv = Attribute("vvv", + "Sets tcpdump -vv option. " + "Even more verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + w = Attribute("w", + "Sets tcpdump -w option. " + "Write the raw packets to file rather than parsing " + "and printing them out.", + type = Types.Bool, + default = False, + flags = Flags.Design) + + expression = Attribute("expression", + "selects which packets will be dumped.", + flags = Flags.Design) + + cls._register_attribute(A) + cls._register_attribute(b) + cls._register_attribute(B) + cls._register_attribute(c) + cls._register_attribute(C) + cls._register_attribute(d) + cls._register_attribute(dd) + cls._register_attribute(ddd) + cls._register_attribute(D) + cls._register_attribute(e) + cls._register_attribute(F) + cls._register_attribute(G) + cls._register_attribute(i) + cls._register_attribute(I) + cls._register_attribute(j) + cls._register_attribute(K) + cls._register_attribute(l) + cls._register_attribute(U) + cls._register_attribute(n) + cls._register_attribute(N) + cls._register_attribute(S) + cls._register_attribute(s) + cls._register_attribute(T) + cls._register_attribute(t) + cls._register_attribute(tt) + cls._register_attribute(ttt) + cls._register_attribute(tttt) + cls._register_attribute(ttttt) + cls._register_attribute(v) + cls._register_attribute(vv) + cls._register_attribute(vvv) + cls._register_attribute(w) + cls._register_attribute(expression) + + def __init__(self, ec, guid): + super(LinuxTcpdump, self).__init__(ec, guid) + self._home = "tcpdump-%s" % self.guid + self._sudo_kill = True + +
[docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("env"): + self.set("env", "PATH=$PATH:/usr/sbin/") + + if not self.get("depends"): + self.set("depends", "tcpdump") + + super(LinuxTcpdump, self).do_deploy() +
+ @property + def _start_command(self): + args = [] + args.append("sudo -S tcpdump") + if self.get("A") == True: + args.append("-A") + if self.get("b") == True: + args.append("-b") + if self.get("B"): + args.append("-B %s" % self.get("B")) + if self.get("c"): + args.append("-c %s" % self.get("c")) + if self.get("C"): + args.append("-C %s" % self.get("C")) + if self.get("d") == True: + args.append("-d") + if self.get("dd") == True: + args.append("-dd") + if self.get("ddd") == True: + args.append("-ddd") + if self.get("D") == True: + args.append("-D") + if self.get("e") == True: + args.append("-e") + if self.get("F"): + args.append("-F %s" % self.get("F")) + if self.get("G") == True: + args.append("-G") + if self.get("i"): + args.append("-i %s" % self.get("i")) + if self.get("I") == True: + args.append("-I") + if self.get("j"): + args.append("-j %s" % self.get("j")) + if self.get("K") == True: + args.append("-K") + if self.get("l") == True: + args.append("-l") + if self.get("U") == True: + args.append("-U") + if self.get("n") == True: + args.append("-n") + if self.get("N") == True: + args.append("-N") + if self.get("S") == True: + args.append("-S") + if self.get("s"): + args.append("-s %s" % self.get("s")) + if self.get("T"): + args.append("-T %s" % self.get("T")) + if self.get("t") == True: + args.append("-t") + if self.get("tt") == True: + args.append("-tt") + if self.get("ttt") == True: + args.append("-ttt") + if self.get("tttt") == True: + args.append("-tttt") + if self.get("ttttt") == True: + args.append("-ttttt") + if self.get("v") == True: + args.append("-v") + if self.get("vv") == True: + args.append("-vv") + if self.get("vvv") == True: + args.append("-vvv") + if self.get("w"): + args.append("-w %s" % self.get("w")) + if self.get("expression"): + args.append(self.get("expression")) + + command = " ".join(args) + + return command + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/traceroute.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/traceroute.html new file mode 100644 index 00000000..21c71a3d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/traceroute.html @@ -0,0 +1,217 @@ + + + + + + + + nepi.resources.linux.traceroute — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.traceroute

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 
+from nepi.resources.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow
+
+import os
+import socket
+
+@clsinit_copy
+
[docs]class LinuxTraceroute(LinuxApplication): + _rtype = "linux::Traceroute" + + @classmethod + def _register_attributes(cls): + countinuous = Attribute("continuous", + "Run traceroute in a while loop", + type = Types.Bool, + default = False, + flags = Flags.Design) + + print_timestamp = Attribute("printTimestamp", + "Print timestamp before running traceroute", + type = Types.Bool, + default = False, + flags = Flags.Design) + + use_ip = Attribute("useIP", + "Use the IP address instead of the host domain name. " + "Useful for environments were dns resolution problems occur " + "frequently", + type = Types.Bool, + default = False, + flags = Flags.Design) + + target = Attribute("target", + "Traceroute target host (host that will be pinged)", + flags = Flags.Design) + + early_start = Attribute("earlyStart", + "Start ping as early as deployment. ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(countinuous) + cls._register_attribute(print_timestamp) + cls._register_attribute(use_ip) + cls._register_attribute(target) + cls._register_attribute(early_start) + + def __init__(self, ec, guid): + super(LinuxTraceroute, self).__init__(ec, guid) + self._home = "traceroute-%s" % self.guid + +
[docs] def upload_start_command(self): + super(LinuxTraceroute, self).upload_start_command() + + if self.get("earlyStart") == True: + self._run_in_background() +
+
[docs] 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).do_deploy() +
+
[docs] def do_start(self): + if self.get("earlyStart") == True: + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg + else: + super(LinuxTraceroute, self).do_start() +
+ @property + def _start_command(self): + args = [] + if self.get("continuous") == True: + args.append("while true; do ") + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + args.append("traceroute") + + target = self.get("target") + if self.get("useIP") == True: + target = socket.gethostbyname(target) + args.append(target) + + if self.get("continuous") == True: + args.append("; sleep 2 ; done ") + + command = " ".join(args) + + return command + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/tun.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tun.html new file mode 100644 index 00000000..f93671e8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tun.html @@ -0,0 +1,127 @@ + + + + + + + + nepi.resources.linux.tun — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.tun

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.linux.tap import LinuxTap
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxTun(LinuxTap): + _rtype = "linux::Tun" + _help = "Creates a TUN device on a Linux host" + + def __init__(self, ec, guid): + super(LinuxTun, self).__init__(ec, guid) + self._vif_prefix = "tun" + self._vif_type = "IFF_TUN" + self._vif_type_flag = LinuxTap.IFF_TUN + self._home = "%s-%s" % (self.vif_prefix, self.guid) + +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/tunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tunnel.html new file mode 100644 index 00000000..6efeb748 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/tunnel.html @@ -0,0 +1,256 @@ + + + + + + + + nepi.resources.linux.tunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.tunnel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+import time
+
+state_check_delay = 0.5
+
+@clsinit_copy
+
[docs]class LinuxTunnel(LinuxApplication): + _rtype = "abstract::linux::Tunnel" + _help = "Constructs a tunnel between two Linux endpoints" + + def __init__(self, ec, guid): + super(LinuxTunnel, self).__init__(ec, guid) + self._home = "tunnel-%s" % self.guid + +
[docs] def log_message(self, msg): + return " guid %d - tunnel %s - %s - %s " % (self.guid, + self.endpoint1.node.get("hostname"), + self.endpoint2.node.get("hostname"), + msg) +
+
[docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + raise NotImplementedError +
+ @property +
[docs] def endpoint1(self): + endpoints = self.get_endpoints() + if endpoints: return endpoints[0] + return None +
+ @property +
[docs] def endpoint2(self): + endpoints = self.get_endpoints() + if endpoints and len(endpoints) > 1: return endpoints[1] + return None +
+
[docs] def app_home(self, endpoint): + return os.path.join(endpoint.node.exp_home, self._home) +
+
[docs] def run_home(self, endpoint): + return os.path.join(self.app_home(endpoint), self.ec.run_id) +
+
[docs] def endpoint_mkdir(self, endpoint): + endpoint.node.mkdir(self.run_home(endpoint)) +
+
[docs] def initiate_connection(self, endpoint, remote_endpoint): + raise NotImplementedError +
+
[docs] def establish_connection(self, endpoint, remote_endpoint, data): + raise NotImplementedError +
+
[docs] def verify_connection(self, endpoint, remote_endpoint): + raise NotImplementedError +
+
[docs] def terminate_connection(self, endpoint, remote_endpoint): + raise NotImplementedError +
+
[docs] def check_state_connection(self, endpoint, remote_endpoint): + raise NotImplementedError +
+
[docs] def do_provision(self): + # create run dir for tunnel on each node + self.endpoint_mkdir(self.endpoint1) + self.endpoint_mkdir(self.endpoint2) + + self.debug("Initiate the connection") + # Start 2 step connection + # Initiate connection from endpoint 1 to endpoint 2 + data1 = self.initiate_connection(self.endpoint1, self.endpoint2) + + # Initiate connection from endpoint 2 to endpoint 1 + data2 = self.initiate_connection(self.endpoint2, self.endpoint1) + + self.debug("Establish the connection") + # Establish connection from endpoint 1 to endpoint 2 + self.establish_connection(self.endpoint1, self.endpoint2, data2) + + # Establish connection from endpoint 2 to endpoint 1 + self.establish_connection(self.endpoint2, self.endpoint1, data1) + + self.debug("Verify the connection") + # check if connection was successful on both sides + self.verify_connection(self.endpoint1, self.endpoint2) + self.verify_connection(self.endpoint2, self.endpoint1) + + self.info("Provisioning finished") + + self.set_provisioned() +
+
[docs] def do_deploy(self): + if (not self.endpoint1 or self.endpoint1.state < ResourceState.READY) or \ + (not self.endpoint2 or self.endpoint2.state < ResourceState.READY): + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_stop(self): + """ Stops application execution + """ + + if self.state == ResourceState.STARTED: + self.info("Stopping tunnel") + + self.terminate_connection(self.endpoint1, self.endpoint2) + self.terminate_connection(self.endpoint2, self.endpoint1) + + self.set_stopped() +
+ @property +
[docs] def state(self): + """ Returns the state of the application + """ + if self._state == ResourceState.STARTED: + # In order to avoid overwhelming the remote host and + # the local processor with too many ssh queries, the state is only + # requested every 'state_check_delay' seconds. + if tdiffsec(tnow(), self._last_state_check) > state_check_delay: + + self.check_state_connection() + + self._last_state_check = tnow() + + return self._state +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptest.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptest.html new file mode 100644 index 00000000..a896201e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptest.html @@ -0,0 +1,461 @@ + + + + + + + + nepi.resources.linux.udptest — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.udptest

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow
+
+import os
+
+@clsinit_copy
+
[docs]class LinuxUdpTest(LinuxApplication): + """ Uses the hpcbench udptest tool to gather UDP measurements. + Measurements require two ends, a server and a client RM. + + http://hpcbench.sourceforge.net/ + """ + _rtype = "linux::UdpTest" + + @classmethod + def _register_attributes(cls): + s = Attribute("s", + "Runs in server mode. ", + type = Types.Bool, + default = False, + 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.Design) + + a = Attribute("a", + "Client option. Perform UDP Round Trip Time (latency) ", + type = Types.Bool, + 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.Design) + + b = Attribute("b", + "Client option. " + "Client UDP buffer size in bytes. Using system default " + "value if not defined.", + type = Types.Integer, + 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.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.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.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.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.Design) + + target = Attribute("target", + "Client option. " + "Hostname or IP address of UDP server. Must be specified.", + flags = Flags.Design) + + i = Attribute("i", + "Client option. " + "Bidirectional UDP throuhgput test. Default is unidirection " + "stream test. ", + type = Types.Bool, + 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.Design) + + m = Attribute("m", + "Client option. " + "Total message size in bytes. 1048576 by default.", + type = Types.Integer, + flags = Flags.Design) + + o = Attribute("o", + "Client option. " + "Output file name. ", + 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.Design) + + q = Attribute("q", + "Client option. " + "Define the TOS field of IP packets. " + "Six values can be used for this setting:\n" + " 1:(IPTOS)-Minimize delay\n" + " 2:(IPTOS)-Maximize throughput\n" + " 3:(DiffServ)-Class1 with low drop probability\n" + " 4:(DiffServ)-class1 with high drop probability\n" + " 5:(DiffServ)-Class4 with low drop probabiltiy\n" + " 6:(DiffServ)-Class4 with high drop probabiltiy\n" + "Write the plot file for gnuplot. Only enable when the output " + "is specified. ", + type = Types.Enumerate, + allowed = ["1", "2", "3", "4", "5", "6"], + flags = Flags.Design) + + r = Attribute("r", + "Client option. " + "Repetition of tests. 10 by default. ", + type = Types.Integer, + flags = Flags.Design) + + t = Attribute("t", + "Client option. " + "Test time constraint in seconds. 5 by default. ", + type = Types.Integer, + flags = Flags.Design) + + T = Attribute("T", + "Client option. " + "Throughput constraint for UDP generator or throughput " + "test. Unlimited by default. ", + type = Types.Integer, + flags = Flags.Design) + + continuous = Attribute("continuous", + "Run nping in a while loop", + type = Types.Bool, + default = False, + flags = Flags.Design) + + print_timestamp = Attribute("printTimestamp", + "Print timestamp before running nping", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(s) + cls._register_attribute(p) + cls._register_attribute(a) + cls._register_attribute(A) + cls._register_attribute(b) + cls._register_attribute(B) + cls._register_attribute(c) + cls._register_attribute(d) + cls._register_attribute(e) + cls._register_attribute(g) + cls._register_attribute(target) + cls._register_attribute(g) + cls._register_attribute(i) + cls._register_attribute(l) + cls._register_attribute(m) + cls._register_attribute(o) + cls._register_attribute(P) + cls._register_attribute(q) + cls._register_attribute(r) + cls._register_attribute(t) + cls._register_attribute(T) + cls._register_attribute(continuous) + cls._register_attribute(print_timestamp) + + def __init__(self, ec, guid): + super(LinuxUdpTest, self).__init__(ec, guid) + self._home = "udptest-%s" % self.guid + +
[docs] def do_deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("sources"): + self.set("sources", self._sources) + + if not self.get("install"): + self.set("install", self._install) + + if not self.get("build"): + self.set("build", self._build) + + if not self.get("env"): + self.set("env", self._environment) + + if not self.get("depends"): + self.set("depends", self._depends) + + super(LinuxUdpTest, self).do_deploy() +
+
[docs] def upload_start_command(self): + super(LinuxUdpTest, self).upload_start_command() + + if self.get("s") == True: + # We want to make sure the server is running + # before the client starts. + # Run the command as a bash script in background, + # in the host ( but wait until the command has + # finished to continue ) + self._run_in_background() +
+
[docs] def do_start(self): + if self.get("s") == True: + # Server is already running + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, err + else: + super(LinuxUdpTest, self).do_start() +
+ @property + def _start_command(self): + args = [] + if self.get("continuous") == True: + args.append("while true; do ") + + if self.get("printTimestamp") == True: + args.append("""echo "`date +'%Y%m%d%H%M%S'`";""") + + if self.get("s") == True: + args.append("udpserver") + else: + args.append("udptest") + + if self.get("p"): + args.append("-p %d" % self.get("p")) + if self.get("a") == True: + args.append("-a") + if self.get("A"): + args.append("-A %d" % self.get("A")) + if self.get("b"): + args.append("-b %d" % self.get("b")) + if self.get("B"): + args.append("-B %d" % self.get("B")) + if self.get("c") == True: + args.append("-c") + if self.get("d"): + args.append("-d %d" % self.get("d")) + if self.get("e") == True: + args.append("-e") + if self.get("g") == True: + args.append("-g") + if self.get("target"): + args.append("-h %s" % self.get("target")) + if self.get("i") == True: + args.append("-i") + if self.get("l"): + args.append("-l %d" % self.get("l")) + if self.get("m"): + args.append("-m %d" % self.get("m")) + if self.get("o"): + args.append("-o %d" % self.get("o")) + if self.get("P"): + args.append("-P %d" % self.get("P")) + if self.get("q"): + args.append("-q %s" % self.get("q")) + if self.get("r"): + args.append("-r %d" % self.get("r")) + if self.get("t"): + args.append("-t %d" % self.get("t")) + if self.get("T"): + args.append("-T %d" % self.get("T")) + + if self.get("continuous") == True: + args.append("; done ") + + command = " ".join(args) + + return command + + @property + def _sources(self): + return "http://hpcbench.sourceforge.net/udp.tar.gz" + + @property + def _depends(self): + return "gcc make" + + @property + def _build(self): + sources = self.get("sources").split(" ")[0] + sources = os.path.basename(sources) + + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/udptest && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, untar and build + " ( " + " mkdir -p ${SRC}/udptest && " + " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/udptest " + " ) && " + "cd ${SRC}/udptest && " + # Just execute and silence warnings... + " ( make ) " + " )") % ({ 'sources': sources, + }) + + @property + def _install(self): + return ( + # Evaluate if ccnx binaries are already installed + " ( " + " test -f ${BIN}/udptest && " + " echo 'binaries found, nothing to do' " + " ) || ( " + # If not, install + " mv ${SRC}/udptest ${BIN} " + " )") + + @property + def _environment(self): + return "PATH=$PATH:${BIN}/udptest" + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptunnel.html new file mode 100644 index 00000000..38d28359 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/linux/udptunnel.html @@ -0,0 +1,245 @@ + + + + + + + + nepi.resources.linux.udptunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.linux.udptunnel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.tunnel import LinuxTunnel
+from nepi.util.sshfuncs import ProcStatus
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+import socket
+import time
+
+@clsinit_copy
+
[docs]class LinuxUdpTunnel(LinuxTunnel): + _rtype = "linux::UdpTunnel" + _help = "Constructs a tunnel between two Linux endpoints using a UDP connection " + _platform = "linux" + + @classmethod + def _register_attributes(cls): + cipher = Attribute("cipher", + "Cipher to encript communication. " + "One of PLAIN, AES, Blowfish, DES, DES3. ", + default = None, + allowed = ["PLAIN", "AES", "Blowfish", "DES", "DES3"], + type = Types.Enumerate, + 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.Design) + + txqueuelen = Attribute("txQueueLen", + "Specifies the interface's transmission queue length. " + "Defaults to 1000. ", + type = Types.Integer, + flags = Flags.Design) + + bwlimit = Attribute("bwLimit", + "Specifies the interface's emulated bandwidth in bytes " + "per second.", + type = Types.Integer, + flags = Flags.Design) + + cls._register_attribute(cipher) + cls._register_attribute(cipher_key) + cls._register_attribute(txqueuelen) + cls._register_attribute(bwlimit) + + def __init__(self, ec, guid): + super(LinuxUdpTunnel, self).__init__(ec, guid) + self._home = "udp-tunnel-%s" % self.guid + self._pids = dict() + +
[docs] def log_message(self, msg): + return " guid %d - udptunnel %s - %s - %s " % (self.guid, + self.endpoint1.node.get("hostname"), + self.endpoint2.node.get("hostname"), + msg) +
+
[docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + connected = [] + for guid in self.connections: + rm = self.ec.get_resource(guid) + if hasattr(rm, "initiate_udp_connection"): + connected.append(rm) + return connected +
+
[docs] def initiate_connection(self, endpoint, remote_endpoint): + cipher = self.get("cipher") + cipher_key = self.get("cipherKey") + bwlimit = self.get("bwLimit") + txqueuelen = self.get("txQueueLen") + connection_app_home = self.app_home(endpoint) + connection_run_home = self.run_home(endpoint) + + port = endpoint.initiate_udp_connection( + remote_endpoint, + connection_app_home, + connection_run_home, + cipher, cipher_key, bwlimit, txqueuelen) + + return port +
+
[docs] def establish_connection(self, endpoint, remote_endpoint, port): + connection_app_home = self.app_home(endpoint) + connection_run_home = self.run_home(endpoint) + + endpoint.establish_udp_connection(remote_endpoint, + connection_app_home, + connection_run_home, + port) +
+
[docs] def verify_connection(self, endpoint, remote_endpoint): + connection_app_home = self.app_home(endpoint) + connection_run_home = self.run_home(endpoint) + + endpoint.verify_connection(remote_endpoint, + connection_app_home, + connection_run_home) +
+
[docs] def terminate_connection(self, endpoint, remote_endpoint): + connection_app_home = self.app_home(endpoint) + connection_run_home = self.run_home(endpoint) + + endpoint.terminate_connection(remote_endpoint, + connection_app_home, + connection_run_home) +
+
[docs] def check_state_connection(self): + # Make sure the process is still running in background + # No execution errors occurred. Make sure the background + # process with the recorded pid is still running. + + status1 = self.endpoint1.check_status() + status2 = self.endpoint2.check_status() + + if status1 == ProcStatus.FINISHED and \ + status2 == ProcStatus.FINISHED: + + # check if execution errors occurred + (out1, err1), proc1 = self.endpoint1.node.check_errors( + self.run_home(self.endpoint1)) + + (out2, err2), proc2 = self.endpoint2.node.check_errors( + self.run_home(self.endpoint2)) + + if err1 or err2: + msg = "Error occurred in tunnel" + self.error(msg, err1, err2) + self.fail() + else: + self.set_stopped() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsapplication.html new file mode 100644 index 00000000..40d168ee --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsapplication.html @@ -0,0 +1,190 @@ + + + + + + + + nepi.resources.netns.netnsapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.resources.netns.netnsbase import NetNSBase
+from nepi.execution.resource import clsinit_copy, ResourceState
+
+import shlex
+
+@clsinit_copy
+
[docs]class NetNSApplication(NetNSBase): + _rtype = "netns::Application" + + def __init__(self, ec, guid): + super(NetNSApplication, self).__init__(ec, guid) + self._traces = dict() + + @classmethod + def _register_attributes(cls): + command = Attribute("command", "Command to execute", flags=Flags.Design) + cls._register_attribute(command) + + @property +
[docs] def emulation(self): + return self.node.emulation +
+ @property +
[docs] def node(self): + from nepi.resources.netns.netnsnode import NetNSNode + node = self.get_connected(NetNSNode.get_rtype()) + + if not node: + msg = "Route not connected to Node!!" + self.error(msg) + raise RuntimeError, msg + + return node[0] +
+ @property + def _rms_to_wait(self): + return [self.node] + +
[docs] def do_start(self): + if self.emulation.state < ResourceState.STARTED: + self.debug("---- RESCHEDULING START ----" ) + self.ec.schedule(self.reschedule_delay, self.start) + else: + self._configure_traces() + + command = shlex.split(self.get("command")) + stdout = self._traces["stdout"] + stderr = self._traces["stderr"] + self._uuid = self.emulation.invoke(self.node.uuid, + "Popen", command, stdout = stdout, + stderr = stderr) + + super(NetNSApplication, self).do_start() + self._start_time = self.emulation.start_time +
+ def _configure_traces(self): + stdout = "%s/%d.stdout" % (self.emulation.run_home, self.guid) + stderr = "%s/%d.stderr" % (self.emulation.run_home, self.guid) + self._trace_filename["stdout"] = stdout + self._trace_filename["stderr"] = stderr + self._traces["stdout"] = self.emulation.create("open", stdout, "w") + self._traces["stderr"] = self.emulation.create("open", stderr, "w") + + @property +
[docs] def state(self): + if self._state == ResourceState.STARTED: + retcode = self.emulation.invoke(self.uuid, "poll") + + if retcode is not None: + if retcode == 0: + self.set_stopped() + else: + out = "" + msg = " Failed to execute command '%s'" % self.get("command") + err = self.trace("stderr") + self.error(msg, out, err) + self.do_fail() + + return self._state +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsbase.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsbase.html new file mode 100644 index 00000000..575244d3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsbase.html @@ -0,0 +1,230 @@ + + + + + + + + nepi.resources.netns.netnsbase — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsbase

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.execution.attribute import Flags
+from nepi.execution.trace import TraceAttr
+
+@clsinit_copy
+
[docs]class NetNSBase(ResourceManager): + _rtype = "abstract::netns::Object" + _platform = "netns" + + def __init__(self, ec, guid): + super(NetNSBase, self).__init__(ec, guid) + self._uuid = None + self._connected = set() + self._trace_filename = dict() + + @property +
[docs] def connected(self): + return self._connected +
+ @property +
[docs] def uuid(self): + return self._uuid +
+
[docs] 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.emulation.trace(filename, attr, block, offset) +
+ @property + def _rms_to_wait(self): + """ Returns the collection of RMs that this RM needs to + wait for before start + + This method should be overriden to wait for other + objects to be deployed before proceeding with the deployment + + """ + raise RuntimeError, "No dependencies defined!" + + def _instantiate_object(self): + pass + + def _wait_rms(self): + rms = set() + for rm in self._rms_to_wait: + if rm is not None: + rms.add(rm) + + """ Returns True if dependent RMs are not yer READY, False otherwise""" + for rm in rms: + if rm.state < ResourceState.READY: + return True + return False + +
[docs] def do_provision(self): + self._instantiate_object() + + self.info("Provisioning finished") + + super(NetNSBase, self).do_provision() +
+
[docs] def do_deploy(self): + if self._wait_rms(): + self.debug("---- RESCHEDULING DEPLOY ----" ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def do_start(self): + if self.state == ResourceState.READY: + # No need to do anything, emulation.Run() will start every object + self.info("Starting") + self.set_started() + else: + msg = " Failed " + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_stop(self): + if self.state == ResourceState.STARTED: + # No need to do anything, emulation.Destroy() will stop every object + self.set_stopped() +
+ @property +
[docs] def state(self): + return self._state +
+
[docs] def get(self, name): + #flags = Flags.NoWrite | Flags.NoRead | Flags.Design + flags = Flags.Design + if self._state in [ResourceState.READY, ResourceState.STARTED] \ + and not self.has_flag(name, flags): + return self.emulation.emu_get(self.uuid, name) + + value = super(NetNSBase, self).get(name) + return value +
+
[docs] def set(self, name, value): + flags = Flags.Design + if (self._state > ResourceState.NEW and \ + self.has_flag(name, Flags.Design)) or \ + self.has_flag(name, Flags.NoWrite): + out = err = "" + msg = " Cannot change Design only attribue %s" % name + self.error(msg, out, err) + return + + if self._state in [ResourceState.READY, ResourceState.STARTED]: + self.emulation.emu_set(self.uuid, name, value) + + value = super(NetNSBase, self).set(name, value) + + return value +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsclient.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsclient.html new file mode 100644 index 00000000..42ff64a3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsclient.html @@ -0,0 +1,132 @@ + + + + + + + + nepi.resources.netns.netnsclient — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsclient

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+
[docs]class NetNSClient(object): + """ Common Interface for NS3 client classes """ + def __init__(self): + super(NetNSClient, self).__init__() + +
[docs] def create(self, *args, **kwargs): + pass +
+
[docs] def invoke(self, *args, **kwargs): + pass +
+
[docs] def set(self, *args, **kwargs): + pass +
+
[docs] def get(self, *args, **kwargs): + pass +
+
[docs] def flush(self, *args, **kwargs): + pass +
+
[docs] def shutdown(self, *args, **kwargs): + pass +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsemulation.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsemulation.html new file mode 100644 index 00000000..6905f11c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsemulation.html @@ -0,0 +1,132 @@ + + + + + + + + nepi.resources.netns.netnsemulation — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsemulation

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+
[docs]class NetNSEmulation(object): + @property +
[docs] def client(self): + return self._client +
+
[docs] def create(self, *args, **kwargs): + return self.client.create(*args, **kwargs) +
+
[docs] def invoke(self, *args, **kwargs): + return self.client.invoke(*args, **kwargs) +
+
[docs] def emu_set(self, *args, **kwargs): + return self.client.set(*args, **kwargs) +
+
[docs] def emu_get(self, *args, **kwargs): + return self.client.get(*args, **kwargs) +
+
[docs] def flush(self, *args, **kwargs): + return self.client.flush(*args, **kwargs) +
+
[docs] def shutdown(self, *args, **kwargs): + return self.client.shutdown(*args, **kwargs) +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsinterface.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsinterface.html new file mode 100644 index 00000000..5d06bce2 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsinterface.html @@ -0,0 +1,117 @@ + + + + + + + + nepi.resources.netns.netnsinterface — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsinterface

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.netns.netnsbase import NetNSBase
+
+@clsinit_copy
+
[docs]class NetNSInterface(NetNSBase): + _rtype = "asbtract::netns::NodeInterface" +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsipv4address.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsipv4address.html new file mode 100644 index 00000000..cf672dff --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsipv4address.html @@ -0,0 +1,153 @@ + + + + + + + + nepi.resources.netns.netnsipv4address — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsipv4address

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.netns.netnsbase import NetNSBase
+
+@clsinit_copy
+
[docs]class NetNSIPv4Address(NetNSBase): + _rtype = "netns::IPv4Address" + + @classmethod + def _register_attributes(cls): + ip = Attribute("ip", "IPv4 address", flags=Flags.Design) + prefix = Attribute("prefix", "IPv4 prefix", flags=Flags.Design) + + cls._register_attribute(ip) + cls._register_attribute(prefix) + + @property +
[docs] def emulation(self): + return self.node.emulation +
+ @property +
[docs] def node(self): + return self.interface.node +
+ @property +
[docs] def interface(self): + from nepi.resources.netns.netnsinterface import NetNSInterface + interface = self.get_connected(NetNSInterface.get_rtype()) + + if not interface: + msg = "IPv4Address not connected to Interface!!" + self.error(msg) + raise RuntimeError, msg + + return interface[0] +
+ @property + def _rms_to_wait(self): + return [self.interface] + + def _instantiate_object(self): + self._uuid = self.emulation.invoke(self.interface.uuid, "add_v4_address", + self.get("ip"), self.get("prefix")) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnode.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnode.html new file mode 100644 index 00000000..6fd67736 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnode.html @@ -0,0 +1,137 @@ + + + + + + + + nepi.resources.netns.netnsnode — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsnode

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.netns.netnsbase import NetNSBase
+
+@clsinit_copy
+
[docs]class NetNSNode(NetNSBase): + _rtype = "netns::Node" + + @property +
[docs] def emulation(self): + from nepi.resources.netns.netnsemulation import NetNSEmulation + + for guid in self.connections: + rm = self.ec.get_resource(guid) + if isinstance(rm, NetNSEmulation): + return rm + + msg = "Node not connected to Emulation" + self.error(msg) + raise RuntimeError, msg +
+ @property + def _rms_to_wait(self): + return [self.emulation] + + def _instantiate_object(self): + self._uuid = self.emulation.create("Node") +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnodeinterface.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnodeinterface.html new file mode 100644 index 00000000..dc017fe7 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsnodeinterface.html @@ -0,0 +1,157 @@ + + + + + + + + nepi.resources.netns.netnsnodeinterface — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsnodeinterface

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.netns.netnsinterface import NetNSInterface
+
+@clsinit_copy
+
[docs]class NetNSNodeInterface(NetNSInterface): + _rtype = "netns::NodeInterface" + + @classmethod + def _register_attributes(cls): + up = Attribute("up", "Interface up", + default = True, + type = Types.Bool) + + cls._register_attribute(up) + + @property +
[docs] def emulation(self): + return self.node.emulation +
+ @property +
[docs] def node(self): + from nepi.resources.netns.netnsnode import NetNSNode + node = self.get_connected(NetNSNode.get_rtype()) + + if not node: + msg = "Route not connected to Node!!" + self.error(msg) + raise RuntimeError, msg + + return node[0] +
+ @property +
[docs] def switch(self): + from nepi.resources.netns.netnsswitch import NetNSSwitch + switch = self.get_connected(NetNSSwitch.get_rtype()) + if switch: return switch[0] + return None +
+ @property + def _rms_to_wait(self): + return [self.node, self.switch] + + def _instantiate_object(self): + self._uuid = self.emulation.invoke(self.node.uuid, "add_if") + self.emulation.invoke(self.switch.uuid, "connect", self.uuid) + self.emulation.emu_set(self.uuid, "up", self.get("up")) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsroute.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsroute.html new file mode 100644 index 00000000..4b4554cc --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsroute.html @@ -0,0 +1,152 @@ + + + + + + + + nepi.resources.netns.netnsroute — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsroute

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.netns.netnsbase import NetNSBase
+
+@clsinit_copy
+
[docs]class NetNSIPv4Route(NetNSBase): + _rtype = "netns::IPv4Route" + + @classmethod + def _register_attributes(cls): + network = Attribute("network", "Network address", flags=Flags.Design) + prefix = Attribute("prefix", "IP prefix length", flags=Flags.Design) + nexthop = Attribute("nexthop", "Nexthop IP", flags=Flags.Design) + + cls._register_attribute(network) + cls._register_attribute(prefix) + cls._register_attribute(nexthop) + + @property +
[docs] def emulation(self): + return self.node.emulation +
+ @property +
[docs] def node(self): + from nepi.resources.netns.netnsnode import NetNSNode + node = self.get_connected(NetNSNode.get_rtype()) + + if not node: + msg = "Route not connected to Node!!" + self.error(msg) + raise RuntimeError, msg + + return node[0] +
+ @property + def _rms_to_wait(self): + return [self.node] + + def _instantiate_object(self): + self._uuid = self.emulation.invoke(self.device.uuid, "add_route", + prefix=self.get("network"), prefix_len=self.get("prefix"), + nexthop=self.get("nexthop")) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsserver.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsserver.html new file mode 100644 index 00000000..c09bfeb0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsserver.html @@ -0,0 +1,307 @@ + + + + + + + + nepi.resources.netns.netnsserver — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsserver

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 netnswrapper import NetNSWrapper
+
+
[docs]class NetNSWrapperMessage: + CREATE = "CREATE" + INVOKE = "INVOKE" + SET = "SET" + GET = "GET" + FLUSH = "FLUSH" + SHUTDOWN = "SHUTDOWN" +
+
[docs]def handle_message(wrapper, msg_type, args, kwargs): + if msg_type == NetNSWrapperMessage.SHUTDOWN: + wrapper.shutdown() + + return "BYEBYE" + + if msg_type == NetNSWrapperMessage.CREATE: + clazzname = args.pop(0) + + return wrapper.create(clazzname, *args) + + if msg_type == NetNSWrapperMessage.INVOKE: + uuid = args.pop(0) + operation = args.pop(0) + + return wrapper.invoke(uuid, operation, *args, **kwargs) + + if msg_type == NetNSWrapperMessage.GET: + uuid = args.pop(0) + name = args.pop(0) + + return wrapper.get(uuid, name) + + if msg_type == NetNSWrapperMessage.SET: + uuid = args.pop(0) + name = args.pop(0) + value = args.pop(0) + + return wrapper.set(uuid, name, value) + + if msg_type == NetNSWrapperMessage.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() + + wrapper.logger.debug("FLUSHED") + + return "FLUSHED" +
+
[docs]def create_socket(socket_name): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(socket_name) + return sock +
+
[docs]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) +
+
[docs]def send_reply(conn, reply): + encoded = base64.b64encode(cPickle.dumps(reply)) + conn.send("%s\n" % encoded) +
+
[docs]def get_options(): + usage = ("usage: %prog -S <socket-name> -D <enable-dump> -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("-D", "--enable-dump", dest="enable_dump", + help = "Enable dumping the remote executed commands to a script " + "in order to later reproduce and debug the experiment", + action = "store_true", + default = False) + + 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.enable_dump) +
+
[docs]def run_server(socket_name, level = logging.INFO, + enable_dump = False): + + ###### wrapper instantiation + if level == logging.DEBUG: + from syslog import LOG_DEBUG + import netns + netns.environ.set_log_level(LOG_DEBUG) + + wrapper = NetNSWrapper(loglevel=level, enable_dump = enable_dump) + + 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 == NetNSWrapperMessage.SHUTDOWN: + stop = True + + try: + reply = handle_message(wrapper, msg_type, args, kwargs) + except: + import traceback + err = traceback.format_exc() + wrapper.logger.error(err) + raise + + try: + send_reply(conn, reply) + except socket.error: + break + + wrapper.logger.info("EXITING...") +
+if __name__ == '__main__': + + (socket_name, verbose, enable_dump) = 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, enable_dump) +
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsswitch.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsswitch.html new file mode 100644 index 00000000..eabd651c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnsswitch.html @@ -0,0 +1,153 @@ + + + + + + + + nepi.resources.netns.netnsswitch — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnsswitch

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.netns.netnsbase import NetNSBase
+
+@clsinit_copy
+
[docs]class NetNSSwitch(NetNSBase): + _rtype = "netns::Switch" + + @classmethod + def _register_attributes(cls): + up = Attribute("up", "Switch up", + default = True, + type = Types.Bool) + + cls._register_attribute(up) + + @property +
[docs] def emulation(self): + return self.node.emulation +
+ @property +
[docs] def node(self): + return self.interface.node +
+ @property +
[docs] def interface(self): + from nepi.resources.netns.netnsinterface import NetNSInterface + interface = self.get_connected(NetNSInterface.get_rtype()) + + if not interface: + msg = "Switch not connected to any Interface!!" + self.error(msg) + raise RuntimeError, msg + + return interface[0] +
+ @property + def _rms_to_wait(self): + return [self.emulation] + + def _instantiate_object(self): + self._uuid = self.emulation.create("Switch") + self.emulation.emu_set(self.uuid, "up", self.get("up")) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper.html new file mode 100644 index 00000000..74dc3173 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper.html @@ -0,0 +1,280 @@ + + + + + + + + nepi.resources.netns.netnswrapper — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnswrapper

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 logging
+import time
+import os
+import sys
+import uuid
+
+
[docs]class NetNSWrapper(object): + def __init__(self, loglevel = logging.INFO, enable_dump = False): + super(NetNSWrapper, self).__init__() + # holds reference to all C++ objects and variables in the simulation + self._objects = dict() + + # Logging + self._logger = logging.getLogger("netnswrapper") + self._logger.setLevel(loglevel) + + # Object to dump instructions to reproduce and debug experiment + from netnswrapper_debug import NetNSWrapperDebuger + self._debuger = NetNSWrapperDebuger(enabled = enable_dump) + + @property +
[docs] def debuger(self): + return self._debuger +
+ @property +
[docs] def logger(self): + return self._logger +
+
[docs] def make_uuid(self): + return "uuid%s" % uuid.uuid4() +
+
[docs] def get_object(self, uuid): + return self._objects.get(uuid) +
+
[docs] def create(self, clazzname, *args): + """ This method should be used to construct netns objects """ + import netns + + if clazzname not in ['open'] and not hasattr(netns, clazzname): + msg = "Type %s not supported" % (clazzname) + self.logger.error(msg) + + uuid = self.make_uuid() + + ### DEBUG + self.logger.debug("CREATE %s( %s )" % (clazzname, str(args))) + + self.debuger.dump_create(uuid, clazzname, args) + ######## + + if clazzname == "open": + path = args[0] + mode = args[1] + obj = open(path, mode) + else: + clazz = getattr(netns, clazzname) + + # 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) + + self._objects[uuid] = obj + + ### DEBUG + self.logger.debug("RET CREATE ( uuid %s ) %s = %s( %s )" % (str(uuid), + str(obj), clazzname, str(args))) + ######## + + return uuid +
+
[docs] def invoke(self, uuid, operation, *args, **kwargs): + newuuid = self.make_uuid() + + ### DEBUG + self.logger.debug("INVOKE %s -> %s( %s, %s ) " % ( + uuid, operation, str(args), str(kwargs))) + + self.debuger.dump_invoke(newuuid, uuid, operation, args, kwargs) + ######## + + obj = self.get_object(uuid) + + method = getattr(obj, operation) + + # arguments starting with 'uuid' identify netns + # objects and must be replaced by the actual object + realargs = self.replace_args(args) + realkwargs = self.replace_kwargs(kwargs) + + result = method(*realargs, **realkwargs) + + # If the result is an object (not a base value), + # then keep track of the object a return the object + # reference (newuuid) + if not (result is None or type(result) in [ + bool, float, long, str, int]): + self._objects[newuuid] = result + result = newuuid + + ### DEBUG + self.logger.debug("RET INVOKE %s%s = %s -> %s(%s, %s) " % ( + "(uuid %s) " % str(newuuid) if newuuid else "", str(result), uuid, + operation, str(args), str(kwargs))) + ######## + + return result +
+
[docs] def set(self, uuid, name, value): + ### DEBUG + self.logger.debug("SET %s %s %s" % (uuid, name, str(value))) + + self.debuger.dump_set(uuid, name, value) + ######## + + obj = self.get_object(uuid) + setattr(obj, name, value) + + ### DEBUG + self.logger.debug("RET SET %s = %s -> set(%s, %s)" % (str(value), uuid, name, + str(value))) + ######## + + return value +
+
[docs] def get(self, uuid, name): + ### DEBUG + self.logger.debug("GET %s %s" % (uuid, name)) + + self.debuger.dump_get(uuid, name) + ######## + + obj = self.get_object(uuid) + result = getattr(obj, name) + + ### DEBUG + self.logger.debug("RET GET %s = %s -> get(%s)" % (str(result), uuid, name)) + ######## + + return result +
+
[docs] def shutdown(self): + ### DEBUG + self.debuger.dump_shutdown() + ######## + + ### FLUSH PIPES + sys.stdout.flush() + sys.stderr.flush() + + ### RELEASE OBJECTS + del self._objects + + ### DEBUG + self.logger.debug("SHUTDOWN") + ######## +
+
[docs] def replace_args(self, args): + realargs = [self.get_object(arg) if \ + str(arg).startswith("uuid") else arg for arg in args] + + return realargs +
+
[docs] 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()]) + + return realkwargs +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper_debug.html b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper_debug.html new file mode 100644 index 00000000..e6af9c76 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/netns/netnswrapper_debug.html @@ -0,0 +1,251 @@ + + + + + + + + nepi.resources.netns.netnswrapper_debug — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.netns.netnswrapper_debug

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+
+############ METHODS DEBUG NETNSWRAPPER EXECUTION
+##
+## The netnswrapper works in ditributed mode, receiving instructions from
+## a remote client. This makes it very hard to debug scripting errors 
+## in the client side. To simplify error debugging, when set to debug mode,
+## the ns3wrapper dumps every executed line to a script that can be then
+## executed locally to reproduce and debug the experiment.
+##
+###########################################################################
+
+import logging
+
+
[docs]class NetNSWrapperDebuger(object): + def __init__(self, enabled): + super(NetNSWrapperDebuger, self).__init__() + self._enabled = enabled + self._script_path = "debug.py" + + self.dump_header() + + @property +
[docs] def enabled(self): + return self._enabled +
+ @property +
[docs] def script_path(self): + return self._script_path +
+
[docs] def dump_to_script(self, command): + f = open(self.script_path, "a") + f.write("%s" % command) + f.close() +
+
[docs] def dump_header(self): + if not self.enabled: + return + + header = """ +from netnswrapper import NetNSWrapper + +wrapper = NS3Wrapper() + +""" + self.dump_to_script(header) +
+
[docs] def dump_factory(self, uuid, type_name, kwargs): + if not self.enabled: + return + + command = ("kwargs = %(kwargs)s\n" + "%(uuid)s = wrapper.factory(%(type_name)s, **kwargs)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "type_name": self.format_value(type_name), + "kwargs": self.format_kwargs(kwargs) + }) + + self.dump_to_script(command) +
+
[docs] def dump_create(self, uuid, clazzname, args): + if not self.enabled: + return + + command = ("args = %(args)s\n" + "%(uuid)s = wrapper.create(%(clazzname)s, *args)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "clazzname": self.format_value(clazzname), + "args": self.format_args(args), + }) + + self.dump_to_script(command) +
+
[docs] def dump_invoke(self, newuuid, uuid, operation, args, kwargs): + if not self.enabled: + return + + command = ("args = %(args)s\n" + "kwargs = %(kwargs)s\n" + "%(newuuid)s = wrapper.invoke(%(uuid)s, %(operation)s, *args, **kwargs)\n\n" + ) % dict({ + "newuuid": self.format_value(newuuid) if newuuid else "nothing", + "uuid": self.format_value(uuid), + "operation": self.format_value(operation), + "args": self.format_args(args), + "kwargs": self.format_kwargs(kwargs), + }) + + self.dump_to_script(command) +
+
[docs] def dump_set(self, uuid, name, value): + if not self.enabled: + return + + command = ("wrapper.set(%(uuid)s, %(name)s, %(value)s)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "name": self.format_value(name), + "value": self.format_value(value), + }) + + self.dump_to_script(command) +
+
[docs] def dump_get(self, uuid, name): + if not self.enabled: + return + + command = ("wrapper.get(%(uuid)s, %(name)s)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "name": self.format_value(name), + }) + + self.dump_to_script(command) +
+
[docs] def dump_shutdown(self): + if not self.enabled: + return + + command = "wrapper.shutdown()\n\n" + self.dump_to_script(command) +
+
[docs] def format_value(self, value): + if isinstance(value, str) and value.startswith("uuid"): + return value.replace("-", "") + + import pprint + return pprint.pformat(value) +
+
[docs] def format_args(self, args): + fargs = map(self.format_value, args) + return "[%s]" % ",".join(fargs) +
+
[docs] def format_kwargs(self, kwargs): + fkwargs = map(lambda (k,w): + "%s: %s" % (self.format_value(k), self.format_value(w)), + kwargs.iteritems()) + + return "dict({%s})" % ",".join(fkwargs) +
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarf_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarf_wifi_manager.html new file mode 100644 index 00000000..74f31e76 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarf_wifi_manager.html @@ -0,0 +1,268 @@ + + + + + + + + nepi.resources.ns3.classes.aarf_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.aarf_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarfcd_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarfcd_wifi_manager.html new file mode 100644 index 00000000..171bd476 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aarfcd_wifi_manager.html @@ -0,0 +1,308 @@ + + + + + + + + nepi.resources.ns3.classes.aarfcd_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.aarfcd_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/adhoc_wifi_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/adhoc_wifi_mac.html new file mode 100644 index 00000000..87e71c70 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/adhoc_wifi_mac.html @@ -0,0 +1,300 @@ + + + + + + + + nepi.resources.ns3.classes.adhoc_wifi_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.adhoc_wifi_mac

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aloha_noack_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aloha_noack_net_device.html new file mode 100644 index 00000000..92e63c07 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/aloha_noack_net_device.html @@ -0,0 +1,168 @@ + + + + + + + + nepi.resources.ns3.classes.aloha_noack_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.aloha_noack_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/amrr_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/amrr_wifi_manager.html new file mode 100644 index 00000000..24d667cd --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/amrr_wifi_manager.html @@ -0,0 +1,268 @@ + + + + + + + + nepi.resources.ns3.classes.amrr_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.amrr_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ap_wifi_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ap_wifi_mac.html new file mode 100644 index 00000000..745cddc4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ap_wifi_mac.html @@ -0,0 +1,340 @@ + + + + + + + + nepi.resources.ns3.classes.ap_wifi_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.ap_wifi_mac

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arf_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arf_wifi_manager.html new file mode 100644 index 00000000..7985d569 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arf_wifi_manager.html @@ -0,0 +1,238 @@ + + + + + + + + nepi.resources.ns3.classes.arf_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.arf_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arp_l3protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arp_l3protocol.html new file mode 100644 index 00000000..7eb70fe4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/arp_l3protocol.html @@ -0,0 +1,146 @@ + + + + + + + + nepi.resources.ns3.classes.arp_l3protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.arp_l3protocol

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3arpl3protocol import NS3BaseArpL3Protocol 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/base_station_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/base_station_net_device.html new file mode 100644 index 00000000..72e712ce --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/base_station_net_device.html @@ -0,0 +1,260 @@ + + + + + + + + nepi.resources.ns3.classes.base_station_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.base_station_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_model.html new file mode 100644 index 00000000..3c6de282 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.binary_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.binary_error_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+
[docs]class NS3BinaryErrorModel(NS3BaseErrorModel): + _rtype = "ns3::BinaryErrorModel" + + @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(NS3BinaryErrorModel, self).__init__(ec, guid) + self._home = "ns3-binary-error-model-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_sixlow_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_sixlow_model.html new file mode 100644 index 00000000..c31a7e7d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/binary_error_sixlow_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.binary_error_sixlow_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.binary_error_sixlow_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+
[docs]class NS3BinaryErrorSixlowModel(NS3BaseErrorModel): + _rtype = "ns3::BinaryErrorSixlowModel" + + @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(NS3BinaryErrorSixlowModel, self).__init__(ec, guid) + self._home = "ns3-binary-error-sixlow-model-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_channel.html new file mode 100644 index 00000000..0477b2f7 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.bridge_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.bridge_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_net_device.html new file mode 100644 index 00000000..ad5f76f9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bridge_net_device.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.bridge_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.bridge_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bulk_send_application.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bulk_send_application.html new file mode 100644 index 00000000..ecefa443 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/bulk_send_application.html @@ -0,0 +1,196 @@ + + + + + + + + nepi.resources.ns3.classes.bulk_send_application — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.bulk_send_application

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/burst_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/burst_error_model.html new file mode 100644 index 00000000..a26a704e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/burst_error_model.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.burst_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.burst_error_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cara_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cara_wifi_manager.html new file mode 100644 index 00000000..36191fdb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cara_wifi_manager.html @@ -0,0 +1,258 @@ + + + + + + + + nepi.resources.ns3.classes.cara_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.cara_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_acceleration_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_acceleration_mobility_model.html new file mode 100644 index 00000000..409cdba1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_acceleration_mobility_model.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.constant_acceleration_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.constant_acceleration_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_position_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_position_mobility_model.html new file mode 100644 index 00000000..b45b8b94 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_position_mobility_model.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.constant_position_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.constant_position_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_rate_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_rate_wifi_manager.html new file mode 100644 index 00000000..5fd39789 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_rate_wifi_manager.html @@ -0,0 +1,238 @@ + + + + + + + + nepi.resources.ns3.classes.constant_rate_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.constant_rate_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.html new file mode 100644 index 00000000..a2c6d187 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_speed_propagation_delay_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.constant_speed_propagation_delay_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.constant_speed_propagation_delay_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationdelaymodel import NS3BasePropagationDelayModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_velocity_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_velocity_mobility_model.html new file mode 100644 index 00000000..45650da0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/constant_velocity_mobility_model.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.constant_velocity_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.constant_velocity_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cost231propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cost231propagation_loss_model.html new file mode 100644 index 00000000..c4c78c5a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/cost231propagation_loss_model.html @@ -0,0 +1,181 @@ + + + + + + + + nepi.resources.ns3.classes.cost231propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.cost231propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_channel.html new file mode 100644 index 00000000..9f64900b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_channel.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.csma_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.csma_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_net_device.html new file mode 100644 index 00000000..5670af2b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/csma_net_device.html @@ -0,0 +1,220 @@ + + + + + + + + nepi.resources.ns3.classes.csma_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.csma_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/drop_tail_queue.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/drop_tail_queue.html new file mode 100644 index 00000000..bad4da12 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/drop_tail_queue.html @@ -0,0 +1,164 @@ + + + + + + + + nepi.resources.ns3.classes.drop_tail_queue — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.drop_tail_queue

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3queue import NS3BaseQueue 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/dsrdsr_routing.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/dsrdsr_routing.html new file mode 100644 index 00000000..624d037c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/dsrdsr_routing.html @@ -0,0 +1,540 @@ + + + + + + + + nepi.resources.ns3.classes.dsrdsr_routing — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.dsrdsr_routing

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+
[docs]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 = "True", + 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/emu_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/emu_net_device.html new file mode 100644 index 00000000..e205dcc3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/emu_net_device.html @@ -0,0 +1,216 @@ + + + + + + + + nepi.resources.ns3.classes.emu_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.emu_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel.html new file mode 100644 index 00000000..ad325985 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.error_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.error_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel_sixlow.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel_sixlow.html new file mode 100644 index 00000000..bb9ca4fd --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_channel_sixlow.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.error_channel_sixlow — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.error_channel_sixlow

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]class NS3ErrorChannelSixlow(NS3BaseChannel): + _rtype = "ns3::ErrorChannelSixlow" + + @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(NS3ErrorChannelSixlow, self).__init__(ec, guid) + self._home = "ns3-error-channel-sixlow-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_net_device.html new file mode 100644 index 00000000..8a3f20c5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/error_net_device.html @@ -0,0 +1,135 @@ + + + + + + + + nepi.resources.ns3.classes.error_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.error_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fd_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fd_net_device.html new file mode 100644 index 00000000..53f07363 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fd_net_device.html @@ -0,0 +1,206 @@ + + + + + + + + nepi.resources.ns3.classes.fd_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.fd_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice 
+
+@clsinit_copy
+
[docs]class NS3FdNetDevice(NS3BaseFdNetDevice): + _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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fixed_rss_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fixed_rss_loss_model.html new file mode 100644 index 00000000..4fb94ab4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/fixed_rss_loss_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.fixed_rss_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.fixed_rss_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/friis_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/friis_propagation_loss_model.html new file mode 100644 index 00000000..abf162de --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/friis_propagation_loss_model.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.friis_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.friis_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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_minloss = Attribute("MinLoss", + "The minimum value (dB) of the total loss, used at short ranges. Note: ", + type = Types.Double, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_minloss) + + + + @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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/gauss_markov_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/gauss_markov_mobility_model.html new file mode 100644 index 00000000..ed9bcb2d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/gauss_markov_mobility_model.html @@ -0,0 +1,246 @@ + + + + + + + + nepi.resources.ns3.classes.gauss_markov_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.gauss_markov_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hierarchical_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hierarchical_mobility_model.html new file mode 100644 index 00000000..a6c94cab --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hierarchical_mobility_model.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.hierarchical_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.hierarchical_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.html new file mode 100644 index 00000000..df1a68c1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/hybrid_buildings_propagation_loss_model.html @@ -0,0 +1,181 @@ + + + + + + + + nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv4l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv4l4protocol.html new file mode 100644 index 00000000..8bf1f9ed --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv4l4protocol.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.icmpv4l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.icmpv4l4protocol

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3icmpv4l4protocol import NS3BaseIcmpv4L4Protocol 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv6l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv6l4protocol.html new file mode 100644 index 00000000..951fec48 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/icmpv6l4protocol.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.icmpv6l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.icmpv6l4protocol

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ideal_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ideal_wifi_manager.html new file mode 100644 index 00000000..f23b5f70 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ideal_wifi_manager.html @@ -0,0 +1,228 @@ + + + + + + + + nepi.resources.ns3.classes.ideal_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.ideal_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ipv4l3protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ipv4l3protocol.html new file mode 100644 index 00000000..1b4d4845 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ipv4l3protocol.html @@ -0,0 +1,206 @@ + + + + + + + + nepi.resources.ns3.classes.ipv4l3protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.ipv4l3protocol

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3ipv4l3protocol import NS3BaseIpv4L3Protocol 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411los_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411los_propagation_loss_model.html new file mode 100644 index 00000000..dff139d4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411los_propagation_loss_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]class NS3ItuR1411LosPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::ItuR1411LosPropagationLossModel" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ItuR1411LosPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-itu-r1411los-propagation-loss-model-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411nlos_over_rooftop_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411nlos_over_rooftop_propagation_loss_model.html new file mode 100644 index 00000000..afc6ba30 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/itu_r1411nlos_over_rooftop_propagation_loss_model.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]class NS3ItuR1411NlosOverRooftopPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::ItuR1411NlosOverRooftopPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_environment = Attribute("Environment", + "Environment Scenario", + type = Types.Enumerate, + default = "Urban", + allowed = ["Urban","SubUrban","OpenAreas"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_environment) + + attr_citysize = Attribute("CitySize", + "Dimension of the city", + type = Types.Enumerate, + default = "Large", + allowed = ["Small","Medium","Large"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_citysize) + + attr_rooftoplevel = Attribute("RooftopLevel", + "The height of the rooftop level in meters", + type = Types.Double, + default = "20", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rooftoplevel) + + attr_streetsorientation = Attribute("StreetsOrientation", + "The orientation of streets in degrees [0,90] with respect to the direction of propagation", + type = Types.Double, + default = "45", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_streetsorientation) + + attr_streetswidth = Attribute("StreetsWidth", + "The width of streets", + type = Types.Double, + default = "20", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_streetswidth) + + attr_buildingsextend = Attribute("BuildingsExtend", + "The distance over which the buildings extend", + type = Types.Double, + default = "80", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_buildingsextend) + + attr_buildingseparation = Attribute("BuildingSeparation", + "The separation between buildings", + type = Types.Double, + default = "50", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_buildingseparation) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3ItuR1411NlosOverRooftopPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-itu-r1411nlos-over-rooftop-propagation-loss-model-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/jakes_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/jakes_propagation_loss_model.html new file mode 100644 index 00000000..7848615f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/jakes_propagation_loss_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.jakes_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.jakes_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/kun2600mhz_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/kun2600mhz_propagation_loss_model.html new file mode 100644 index 00000000..8d1f117f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/kun2600mhz_propagation_loss_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]class NS3Kun2600MhzPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::Kun2600MhzPropagationLossModel" + + @classmethod + def _register_attributes(cls): + pass + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3Kun2600MhzPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-kun2600mhz-propagation-loss-model-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/list_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/list_error_model.html new file mode 100644 index 00000000..eaa1c9e5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/list_error_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.list_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.list_error_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/log_distance_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/log_distance_propagation_loss_model.html new file mode 100644 index 00000000..aa34c047 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/log_distance_propagation_loss_model.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.log_distance_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.log_distance_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/loopback_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/loopback_net_device.html new file mode 100644 index 00000000..fb9b40ca --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/loopback_net_device.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.loopback_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.loopback_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lr_wpan_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lr_wpan_net_device.html new file mode 100644 index 00000000..f85e8a87 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lr_wpan_net_device.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.lr_wpan_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.lr_wpan_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]class NS3LrWpanNetDevice(NS3BaseNetDevice): + _rtype = "ns3::LrWpanNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_useacks = Attribute("UseAcks", + "Request acknowledgments for data frames.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_useacks) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3LrWpanNetDevice, self).__init__(ec, guid) + self._home = "ns3-lr-wpan-net-device-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_enb_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_enb_net_device.html new file mode 100644 index 00000000..61bab79f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_enb_net_device.html @@ -0,0 +1,211 @@ + + + + + + + + nepi.resources.ns3.classes.lte_enb_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.lte_enb_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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_csgid = Attribute("CsgId", + "The Closed Subscriber Group (CSG) identity that this eNodeB belongs to", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_csgid) + + attr_csgindication = Attribute("CsgIndication", + "If true, only UEs which are members of the CSG (i.e. same CSG ID) can gain access to the eNodeB, therefore enforcing closed access mode. Otherwise, the eNodeB operates as a non-CSG cell and implements open access mode.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_csgindication) + + 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_simple_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_simple_net_device.html new file mode 100644 index 00000000..69e64841 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_simple_net_device.html @@ -0,0 +1,135 @@ + + + + + + + + nepi.resources.ns3.classes.lte_simple_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.lte_simple_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_ue_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_ue_net_device.html new file mode 100644 index 00000000..2ed03a61 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/lte_ue_net_device.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.lte_ue_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.lte_ue_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]class NS3LteUeNetDevice(NS3BaseNetDevice): + _rtype = "ns3::LteUeNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_imsi = Attribute("Imsi", + "International Mobile Subscriber Identity assigned to this UE", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_imsi) + + 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_csgid = Attribute("CsgId", + "The Closed Subscriber Group (CSG) identity that this UE is associated with, i.e., giving the UE access to cells which belong to this particular CSG. This restriction only applies to initial cell selection and EPC-enabled simulation. This does not revoke the UE\'s access to non-CSG cells. ", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_csgid) + + 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(NS3LteUeNetDevice, self).__init__(ec, guid) + self._home = "ns3-lte-ue-net-device-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/matrix_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/matrix_propagation_loss_model.html new file mode 100644 index 00000000..91e9fbe2 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/matrix_propagation_loss_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.matrix_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.matrix_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_point_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_point_device.html new file mode 100644 index 00000000..aae79d55 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_point_device.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.mesh_point_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.mesh_point_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_wifi_interface_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_wifi_interface_mac.html new file mode 100644 index 00000000..87af1d64 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/mesh_wifi_interface_mac.html @@ -0,0 +1,330 @@ + + + + + + + + nepi.resources.ns3.classes.mesh_wifi_interface_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.mesh_wifi_interface_mac

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/minstrel_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/minstrel_wifi_manager.html new file mode 100644 index 00000000..2c01269a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/minstrel_wifi_manager.html @@ -0,0 +1,268 @@ + + + + + + + + nepi.resources.ns3.classes.minstrel_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.minstrel_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/multi_model_spectrum_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/multi_model_spectrum_channel.html new file mode 100644 index 00000000..c80bd72b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/multi_model_spectrum_channel.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.multi_model_spectrum_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.multi_model_spectrum_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nakagami_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nakagami_propagation_loss_model.html new file mode 100644 index 00000000..17d6e92e --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nakagami_propagation_loss_model.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.nakagami_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.nakagami_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nist_error_rate_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nist_error_rate_model.html new file mode 100644 index 00000000..d6924009 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/nist_error_rate_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.nist_error_rate_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.nist_error_rate_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3errorratemodel import NS3BaseErrorRateModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/node.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/node.html new file mode 100644 index 00000000..dfc75d30 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/node.html @@ -0,0 +1,151 @@ + + + + + + + + nepi.resources.ns3.classes.node — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.node

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3node import NS3BaseNode 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/non_communicating_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/non_communicating_net_device.html new file mode 100644 index 00000000..40302c41 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/non_communicating_net_device.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.non_communicating_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.non_communicating_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ocb_wifi_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ocb_wifi_mac.html new file mode 100644 index 00000000..fe0ad5f4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ocb_wifi_mac.html @@ -0,0 +1,300 @@ + + + + + + + + nepi.resources.ns3.classes.ocb_wifi_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.ocb_wifi_mac

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
+
+@clsinit_copy
+
[docs]class NS3OcbWifiMac(NS3BaseWifiMac): + _rtype = "ns3::OcbWifiMac" + + @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(NS3OcbWifiMac, self).__init__(ec, guid) + self._home = "ns3-ocb-wifi-mac-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.html new file mode 100644 index 00000000..ceaa4abb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/oh_buildings_propagation_loss_model.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.oh_buildings_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.oh_buildings_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/okumura_hata_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/okumura_hata_propagation_loss_model.html new file mode 100644 index 00000000..6426f914 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/okumura_hata_propagation_loss_model.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.okumura_hata_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.okumura_hata_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]class NS3OkumuraHataPropagationLossModel(NS3BasePropagationLossModel): + _rtype = "ns3::OkumuraHataPropagationLossModel" + + @classmethod + def _register_attributes(cls): + + attr_frequency = Attribute("Frequency", + "The propagation frequency in Hz", + type = Types.Double, + default = "2.16e+09", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_frequency) + + attr_environment = Attribute("Environment", + "Environment Scenario", + type = Types.Enumerate, + default = "Urban", + allowed = ["Urban","SubUrban","OpenAreas"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_environment) + + attr_citysize = Attribute("CitySize", + "Dimension of the city", + type = Types.Enumerate, + default = "Large", + allowed = ["Small","Medium","Large"], + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_citysize) + + + + @classmethod + def _register_traces(cls): + pass + + def __init__(self, ec, guid): + super(NS3OkumuraHataPropagationLossModel, self).__init__(ec, guid) + self._home = "ns3-okumura-hata-propagation-loss-model-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/on_off_application.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/on_off_application.html new file mode 100644 index 00000000..d077a617 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/on_off_application.html @@ -0,0 +1,226 @@ + + + + + + + + nepi.resources.ns3.classes.on_off_application — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.on_off_application

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/onoe_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/onoe_wifi_manager.html new file mode 100644 index 00000000..5a657309 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/onoe_wifi_manager.html @@ -0,0 +1,248 @@ + + + + + + + + nepi.resources.ns3.classes.onoe_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.onoe_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/packet_sink.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/packet_sink.html new file mode 100644 index 00000000..06afb05a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/packet_sink.html @@ -0,0 +1,176 @@ + + + + + + + + nepi.resources.ns3.classes.packet_sink — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.packet_sink

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ping6.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ping6.html new file mode 100644 index 00000000..7800ecfa --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/ping6.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.ping6 — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.ping6

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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 = "::", + 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 = "::", + 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_channel.html new file mode 100644 index 00000000..9633c160 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_channel.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.point_to_point_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.point_to_point_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_net_device.html new file mode 100644 index 00000000..b03bacfe --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_net_device.html @@ -0,0 +1,216 @@ + + + + + + + + nepi.resources.ns3.classes.point_to_point_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.point_to_point_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_remote_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_remote_channel.html new file mode 100644 index 00000000..06166e88 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/point_to_point_remote_channel.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.point_to_point_remote_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.point_to_point_remote_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/radvd.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/radvd.html new file mode 100644 index 00000000..0aa42df4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/radvd.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.radvd — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.radvd

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_direction2d_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_direction2d_mobility_model.html new file mode 100644 index 00000000..22efa324 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_direction2d_mobility_model.html @@ -0,0 +1,186 @@ + + + + + + + + nepi.resources.ns3.classes.random_direction2d_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.random_direction2d_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_delay_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_delay_model.html new file mode 100644 index 00000000..013f9fd8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_delay_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.random_propagation_delay_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.random_propagation_delay_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationdelaymodel import NS3BasePropagationDelayModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_loss_model.html new file mode 100644 index 00000000..67dfe0f8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_propagation_loss_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.random_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.random_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_walk2d_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_walk2d_mobility_model.html new file mode 100644 index 00000000..2baf6a81 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_walk2d_mobility_model.html @@ -0,0 +1,216 @@ + + + + + + + + nepi.resources.ns3.classes.random_walk2d_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.random_walk2d_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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|100|0|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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_waypoint_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_waypoint_mobility_model.html new file mode 100644 index 00000000..c2549aeb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/random_waypoint_mobility_model.html @@ -0,0 +1,176 @@ + + + + + + + + nepi.resources.ns3.classes.random_waypoint_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.random_waypoint_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/range_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/range_propagation_loss_model.html new file mode 100644 index 00000000..12a038c1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/range_propagation_loss_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.range_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.range_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rate_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rate_error_model.html new file mode 100644 index 00000000..df1f4f9f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rate_error_model.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.rate_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.rate_error_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/receive_list_error_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/receive_list_error_model.html new file mode 100644 index 00000000..dcf10c00 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/receive_list_error_model.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.receive_list_error_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.receive_list_error_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3errormodel import NS3BaseErrorModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/red_queue.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/red_queue.html new file mode 100644 index 00000000..1a49a0f9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/red_queue.html @@ -0,0 +1,264 @@ + + + + + + + + nepi.resources.ns3.classes.red_queue — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.red_queue

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3queue import NS3BaseQueue 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rraa_wifi_manager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rraa_wifi_manager.html new file mode 100644 index 00000000..68fa6daf --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/rraa_wifi_manager.html @@ -0,0 +1,458 @@ + + + + + + + + nepi.resources.ns3.classes.rraa_wifi_manager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.rraa_wifi_manager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiremotestationmanager import NS3BaseWifiRemoteStationManager 
+
+@clsinit_copy
+
[docs]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-2012, Section 9.3.5. 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-2012, Section 9.5. 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_channel.html new file mode 100644 index 00000000..afa2fd81 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.simple_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.simple_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_net_device.html new file mode 100644 index 00000000..da4586bb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/simple_net_device.html @@ -0,0 +1,135 @@ + + + + + + + + nepi.resources.ns3.classes.simple_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.simple_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/single_model_spectrum_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/single_model_spectrum_channel.html new file mode 100644 index 00000000..7570e780 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/single_model_spectrum_channel.html @@ -0,0 +1,156 @@ + + + + + + + + nepi.resources.ns3.classes.single_model_spectrum_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.single_model_spectrum_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/six_low_pan_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/six_low_pan_net_device.html new file mode 100644 index 00000000..d4be2bb4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/six_low_pan_net_device.html @@ -0,0 +1,214 @@ + + + + + + + + nepi.resources.ns3.classes.six_low_pan_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.six_low_pan_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]class NS3SixLowPanNetDevice(NS3BaseNetDevice): + _rtype = "ns3::SixLowPanNetDevice" + + @classmethod + def _register_attributes(cls): + + attr_rfc6282 = Attribute("Rfc6282", + "Use RFC6282 (IPHC) if true, RFC4944 (HC1) otherwise.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_rfc6282) + + attr_omitudpchecksum = Attribute("OmitUdpChecksum", + "Omit the UDP checksum in IPHC compression.", + type = Types.Bool, + default = "True", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_omitudpchecksum) + + attr_fragmentreassemblylistsize = Attribute("FragmentReassemblyListSize", + "The maximum size of the reassembly buffer (in packets). Zero meaning infinite.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentreassemblylistsize) + + attr_fragmentexpirationtimeout = Attribute("FragmentExpirationTimeout", + "When this timeout expires, the fragments will be cleared from the buffer.", + type = Types.String, + default = "+60000000000.0ns", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_fragmentexpirationtimeout) + + attr_compressionthreshold = Attribute("CompressionThreshold", + "The minimum MAC layer payload size.", + type = Types.Integer, + default = "0", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_compressionthreshold) + + attr_forceethertype = Attribute("ForceEtherType", + "Force a specific EtherType in L2 frames.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_forceethertype) + + attr_ethertype = Attribute("EtherType", + "The specific EtherType to be used in L2 frames.", + type = Types.Integer, + default = "65535", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_ethertype) + + + + @classmethod + def _register_traces(cls): + + tx = Trace("Tx", "Send - packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index.") + + cls._register_trace(tx) + + rx = Trace("Rx", "Receive - packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index.") + + cls._register_trace(rx) + + drop = Trace("Drop", "Drop - DropReason, packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index.") + + cls._register_trace(drop) + + + + def __init__(self, ec, guid): + super(NS3SixLowPanNetDevice, self).__init__(ec, guid) + self._home = "ns3-six-low-pan-net-device-%s" % self.guid
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/sta_wifi_mac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/sta_wifi_mac.html new file mode 100644 index 00000000..d695e43f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/sta_wifi_mac.html @@ -0,0 +1,348 @@ + + + + + + + + nepi.resources.ns3.classes.sta_wifi_mac — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.sta_wifi_mac

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifimac import NS3BaseWifiMac 
+
+@clsinit_copy
+
[docs]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_activeprobing = Attribute("ActiveProbing", + "If true, we send probe requests. If false, we don\'t. NOTE: if more than one STA in your simulation is using active probing, you should enable it at a different simulation time for each STA, otherwise all the STAs will start sending probes at the same time resulting in collisions. See bug 1060 for more info.", + type = Types.Bool, + default = "False", + allowed = None, + range = None, + flags = Flags.Reserved | Flags.Construct) + + cls._register_attribute(attr_activeprobing) + + 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.html new file mode 100644 index 00000000..03aaaedc --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/steady_state_random_waypoint_mobility_model.html @@ -0,0 +1,246 @@ + + + + + + + + nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/subscriber_station_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/subscriber_station_net_device.html new file mode 100644 index 00000000..45bace14 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/subscriber_station_net_device.html @@ -0,0 +1,306 @@ + + + + + + + + nepi.resources.ns3.classes.subscriber_station_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.subscriber_station_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tap_bridge.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tap_bridge.html new file mode 100644 index 00000000..0f26c6be --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tap_bridge.html @@ -0,0 +1,211 @@ + + + + + + + + nepi.resources.ns3.classes.tap_bridge — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.tap_bridge

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tcp_l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tcp_l4protocol.html new file mode 100644 index 00000000..27e51dbd --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/tcp_l4protocol.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.tcp_l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.tcp_l4protocol

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.html new file mode 100644 index 00000000..458f0bbe --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/three_log_distance_propagation_loss_model.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.three_log_distance_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.three_log_distance_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.html new file mode 100644 index 00000000..3a34d749 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/two_ray_ground_propagation_loss_model.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3propagationlossmodel import NS3BasePropagationLossModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/uan_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/uan_channel.html new file mode 100644 index 00000000..4e17dfd4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/uan_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.uan_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.uan_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3channel import NS3BaseChannel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_client.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_client.html new file mode 100644 index 00000000..a86a67d3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_client.html @@ -0,0 +1,201 @@ + + + + + + + + nepi.resources.ns3.classes.udp_client — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.udp_client

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_client.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_client.html new file mode 100644 index 00000000..245eb6d0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_client.html @@ -0,0 +1,206 @@ + + + + + + + + nepi.resources.ns3.classes.udp_echo_client — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.udp_echo_client

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_server.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_server.html new file mode 100644 index 00000000..582ce26d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_echo_server.html @@ -0,0 +1,161 @@ + + + + + + + + nepi.resources.ns3.classes.udp_echo_server — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.udp_echo_server

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_l4protocol.html new file mode 100644 index 00000000..9a2086a8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_l4protocol.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.udp_l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.udp_l4protocol

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_server.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_server.html new file mode 100644 index 00000000..8688d338 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_server.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.classes.udp_server — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.udp_server

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_trace_client.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_trace_client.html new file mode 100644 index 00000000..266ecd7d --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/udp_trace_client.html @@ -0,0 +1,181 @@ + + + + + + + + nepi.resources.ns3.classes.udp_trace_client — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.udp_trace_client

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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 (including the SeqTsHeader, 12 bytes).", + 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/v4ping.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/v4ping.html new file mode 100644 index 00000000..3dd63cd5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/v4ping.html @@ -0,0 +1,196 @@ + + + + + + + + nepi.resources.ns3.classes.v4ping — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.v4ping

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/virtual_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/virtual_net_device.html new file mode 100644 index 00000000..82adaa9a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/virtual_net_device.html @@ -0,0 +1,162 @@ + + + + + + + + nepi.resources.ns3.classes.virtual_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.virtual_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/waypoint_mobility_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/waypoint_mobility_model.html new file mode 100644 index 00000000..54460890 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/waypoint_mobility_model.html @@ -0,0 +1,186 @@ + + + + + + + + nepi.resources.ns3.classes.waypoint_mobility_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.waypoint_mobility_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/wifi_net_device.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/wifi_net_device.html new file mode 100644 index 00000000..86375c83 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/wifi_net_device.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.wifi_net_device — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.wifi_net_device

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifinetdevice import NS3BaseWifiNetDevice 
+
+@clsinit_copy
+
[docs]class NS3WifiNetDevice(NS3BaseWifiNetDevice): + _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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_error_rate_model.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_error_rate_model.html new file mode 100644 index 00000000..f4c77474 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_error_rate_model.html @@ -0,0 +1,130 @@ + + + + + + + + nepi.resources.ns3.classes.yans_error_rate_model — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.yans_error_rate_model

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3errorratemodel import NS3BaseErrorRateModel 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_channel.html new file mode 100644 index 00000000..658f1b87 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.classes.yans_wifi_channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.yans_wifi_channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifichannel import NS3BaseWifiChannel 
+
+@clsinit_copy
+
[docs]class NS3YansWifiChannel(NS3BaseWifiChannel): + _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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_phy.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_phy.html new file mode 100644 index 00000000..6cb03971 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/classes/yans_wifi_phy.html @@ -0,0 +1,344 @@ + + + + + + + + nepi.resources.ns3.classes.yans_wifi_phy — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.classes.yans_wifi_phy

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3wifiphy import NS3BaseWifiPhy 
+
+@clsinit_copy
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3application.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3application.html new file mode 100644 index 00000000..755f4783 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3application.html @@ -0,0 +1,181 @@ + + + + + + + + nepi.resources.ns3.ns3application — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3application

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3base import NS3Base
+
+@clsinit_copy
+
[docs]class NS3BaseApplication(NS3Base): + _rtype = "abstract::ns3::Application" + + def __init__(self, ec, guid): + super(NS3BaseApplication, self).__init__(ec, guid) + self._node = None + + @property +
[docs] def node(self): + if not self._node: + 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 + + self._node = nodes[0] + + return self._node +
+ @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) + +
[docs] 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() +
+
[docs] def do_start(self): + if self.simulation.state < ResourceState.STARTED: + self.debug("---- RESCHEDULING START ----" ) + self.ec.schedule(self.reschedule_delay, self.start) + else: + super(NS3BaseApplication, self).do_start() + self._start_time = self.simulation.start_time +
+ @property +
[docs] def state(self): + if self._state == ResourceState.STARTED: + try: + is_running = self.simulation.invoke(self.uuid, "isAppRunning") + + if not is_running: + self.set_stopped() + except: + msg = "Application failed. Can not retrieve state" + out = "" + + import traceback + err = traceback.format_exc() + self.error(msg, out, err) + self.do_fail() + + return self._state +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3arpl3protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3arpl3protocol.html new file mode 100644 index 00000000..ad7db8ed --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3arpl3protocol.html @@ -0,0 +1,137 @@ + + + + + + + + nepi.resources.ns3.ns3arpl3protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3arpl3protocol

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseArpL3Protocol(NS3Base): + _rtype = "abstract::ns3::ArpL3Protocol" + + @property +
[docs] 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.simulation) + return rms + + def _connect_object(self): + pass
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3base.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3base.html new file mode 100644 index 00000000..dd54a0c9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3base.html @@ -0,0 +1,257 @@ + + + + + + + + nepi.resources.ns3.ns3base — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3base

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.execution.attribute import Flags
+from nepi.execution.trace import TraceAttr
+
+@clsinit_copy
+
[docs]class NS3Base(ResourceManager): + _rtype = "abstract::ns3::Object" + _platform = "ns3" + + def __init__(self, ec, guid): + super(NS3Base, self).__init__(ec, guid) + self._uuid = None + self._connected = set() + self._trace_filename = dict() + self._node = None + + @property +
[docs] def connected(self): + return self._connected +
+ @property +
[docs] def uuid(self): + return self._uuid +
+ @property +
[docs] def simulation(self): + return self.node.simulation +
+ @property +
[docs] def node(self): + if not self._node: + from nepi.resources.ns3.ns3node import NS3BaseNode + nodes = self.get_connected(NS3BaseNode.get_rtype()) + if nodes: self._node = nodes[0] + + return self._node +
+
[docs] 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.state < ResourceState.READY: + return True + return False + +
[docs] def do_provision(self): + self._instantiate_object() + self._connect_object() + self._configure_object() + + self.info("Provisioning finished") + + super(NS3Base, self).do_provision() +
+
[docs] def do_deploy(self): + if self._wait_rms(): + self.debug("---- RESCHEDULING DEPLOY ----" ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] 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 +
+
[docs] def do_stop(self): + if self.state == ResourceState.STARTED: + # No need to do anything, simulation.Destroy() will stop every object + self.info("Stopping") + self.set_stopped() +
+ @property +
[docs] def state(self): + return self._state +
+
[docs] 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 +
+
[docs] 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 +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ccndceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ccndceapplication.html new file mode 100644 index 00000000..273de635 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ccndceapplication.html @@ -0,0 +1,212 @@ + + + + + + + + nepi.resources.ns3.ns3ccndceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3ccndceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication
+
+import os
+import threading
+
+@clsinit_copy
+
[docs]class NS3BaseCCNDceApplication(NS3BaseDceApplication): + _rtype = "abstract::ns3::CCNDceApplication" + + # Lock used to synchronize usage of CcnClientHelper + ccn_client_lock = threading.Lock() + _ccn_client_helper_uuid = None + + @property +
[docs] def ccn_client_helper_uuid(self): + if not self._ccn_client_helper_uuid: + self._ccn_client_helper_uuid = self.simulation.create("CcnClientHelper") + return self._ccn_client_helper_uuid +
+ 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.ccn_client_lock: + self.simulation.invoke( + self.ccn_client_helper_uuid, + "ResetArguments") + + self.simulation.invoke( + self.ccn_client_helper_uuid, + "ResetEnvironment") + + self.simulation.invoke( + self.ccn_client_helper_uuid, + "SetBinary", self.get("binary")) + + self.simulation.invoke( + self.ccn_client_helper_uuid, + "SetStackSize", self.get("stackSize")) + + arguments = self.get("arguments") + if arguments: + for arg in map(str.strip, arguments.split(";")): + self.simulation.invoke( + self.ccn_client_helper_uuid, + "AddArgument", arg) + + environment = self.get("environment") + if environment: + for env in map(str.strip, environment.split(";")): + key, val = env.split("=") + self.simulation.invoke( + self.ccn_client_helper_uuid, + "AddEnvironment", key, val) + + if self.has_attribute("files"): + files = self.get("files") + if files: + for file in map(str.strip, files.split(";")): + remotepath, dcepath = file.split("=") + localpath = os.path.join(self.simulation.app_home, + os.path.basename(remotepath)) + self.simulation.invoke( + self.ccn_client_helper_uuid, + "AddFile", localpath, dcepath) + + if self.has_attribute("stdinFile"): + stdinfile = self.get("stdinFile") + if stdinfile: + # stdinfile might be an empty text that should be set as + # stdin + self.simulation.invoke( + self.ccn_client_helper_uuid, + "SetStdinFile", stdinfile) + + apps_uuid = self.simulation.invoke( + self.ccn_client_helper_uuid, + "InstallInNode", self.node.uuid) + + """ + container_uuid = self.simulation.create("NodeContainer") + self.simulation.invoke(container_uuid, "Add", self.node.uuid) + apps_uuid = self.simulation.invoke( + self.ccn_client_helper_uuid, + "Install", container_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")) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3channel.html new file mode 100644 index 00000000..cc8246d0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3channel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.ns3channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseChannel(NS3Base): + _rtype = "abstract::ns3::Channel" + + @property +
[docs] def simulation(self): + return self.devices[0].node.simulation +
+ @property +
[docs] 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 +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3client.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3client.html new file mode 100644 index 00000000..7e94ddcc --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3client.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.ns3client — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3client

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+
[docs]class NS3Client(object): + """ Common Interface for NS3 client classes """ + def __init__(self): + super(NS3Client, self).__init__() + +
[docs] def create(self, *args, **kwargs): + pass +
+
[docs] def factory(self, *args, **kwargs): + pass +
+
[docs] def invoke(self, *args, **kwargs): + pass +
+
[docs] def set(self, *args, **kwargs): + pass +
+
[docs] def get(self, *args, **kwargs): + pass +
+
[docs] def flush(self, *args, **kwargs): + pass +
+
[docs] def start(self, *args, **kwargs): + pass +
+
[docs] def stop(self, *args, **kwargs): + pass +
+
[docs] def shutdown(self, *args, **kwargs): + pass +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dceapplication.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dceapplication.html new file mode 100644 index 00000000..87795b99 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dceapplication.html @@ -0,0 +1,272 @@ + + + + + + + + nepi.resources.ns3.ns3dceapplication — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3dceapplication

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.ns3.ns3application import NS3BaseApplication
+from nepi.execution.trace import TraceAttr
+
+from nepi.resources.ns3.ns3wrapper import SIMULATOR_UUID
+
+import os
+import time
+import threading
+        
+@clsinit_copy
+
[docs]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) + + use_dlm = Attribute("useDlmLoader", + "Use ns3::DlmLoaderFactory as library loader", + type = Types.Bool, + 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(binary) + cls._register_attribute(stack_size) + cls._register_attribute(arguments) + cls._register_attribute(environment) + cls._register_attribute(use_dlm) + cls._register_attribute(stoptime) + cls._register_attribute(starttime) + + def __init__(self, ec, guid): + super(NS3BaseDceApplication, self).__init__(ec, guid) + self._pid = None + + @property +
[docs] def pid(self): + return self._pid +
+ 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 + dce_helper = self.simulation.dce_helper + + with dce_helper.dce_application_lock: + dce_app_uuid = dce_helper.dce_application_uuid + + self.simulation.invoke(dce_app_uuid, "ResetArguments") + + self.simulation.invoke(dce_app_uuid, "ResetEnvironment") + + self.simulation.invoke(dce_app_uuid, + "SetBinary", self.get("binary")) + + self.simulation.invoke(dce_app_uuid, + "SetStackSize", self.get("stackSize")) + + arguments = self.get("arguments") + if arguments: + for arg in map(str.strip, arguments.split(";")): + self.simulation.invoke(dce_app_uuid, + "AddArgument", arg) + + environment = self.get("environment") + if environment: + for env in map(str.strip, environment.split(";")): + key, val = env.split("=") + self.simulation.invoke(dce_app_uuid, + "AddEnvironment", key, val) + + apps_uuid = self.simulation.invoke(dce_app_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")) + +
[docs] 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() +
+
[docs] def do_start(self): + if self.simulation.state < ResourceState.STARTED: + self.debug("---- RESCHEDULING START ----" ) + self.ec.schedule(self.reschedule_delay, self.start) + else: + is_app_started = self.simulation.invoke(self.uuid, "isAppStarted") + + if is_app_started or self.simulation.state > ResourceState.STARTED: + super(NS3BaseApplication, self).do_start() + self._start_time = self.simulation.start_time + else: + # Reschedule until dce application is actually started + self.debug("---- RESCHEDULING START ----" ) + self.ec.schedule(self.reschedule_delay, self.start) +
+
[docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + self._configure_traces() + return super(NS3BaseDceApplication, self).trace(name, attr = attr, + block = block, offset = offset) +
+ def _configure_traces(self): + if self.pid is not None: + return + + # Using lock to prevent concurrent access to the DceApplicationHelper + # from different DceApplication RMs + dce_helper = self.simulation.dce_helper + + with dce_helper.dce_application_lock: + dce_app_uuid = dce_helper.dce_application_uuid + + self._pid = self.simulation.invoke(dce_app_uuid, + "GetPid", self.uuid) + + node_id = self.node.node_id + self._trace_filename["stdout"] = "files-%s/var/log/%s/stdout" % (node_id, self.pid) + self._trace_filename["stderr"] = "files-%s/var/log/%s/stderr" % (node_id, self.pid) + self._trace_filename["status"] = "files-%s/var/log/%s/status" % (node_id, self.pid) + self._trace_filename["cmdline"] = "files-%s/var/log/%s/cmdline" % (node_id, self.pid) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dcehelper.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dcehelper.html new file mode 100644 index 00000000..6c104f30 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3dcehelper.html @@ -0,0 +1,149 @@ + + + + + + + + nepi.resources.ns3.ns3dcehelper — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3dcehelper

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 os
+import time
+import threading
+        
+
[docs]class NS3DceHelper(object): + def __init__(self, simulation): + self.simulation = simulation + + # 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() + + self._dce_manager_uuid = None + self._dce_application_uuid = None + + @property +
[docs] def dce_manager_uuid(self): + if not self._dce_manager_uuid: + self._dce_manager_uuid = \ + self.simulation.create("DceManagerHelper") + + return self._dce_manager_uuid +
+ @property +
[docs] def dce_application_uuid(self): + if not self._dce_application_uuid: + self._dce_application_uuid = \ + self.simulation.create("DceApplicationHelper") + + return self._dce_application_uuid +
+ @property +
[docs] def dce_manager_lock(self): + return self._dce_manager_lock +
+ @property +
[docs] def dce_application_lock(self): + return self._dce_application_lock +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errormodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errormodel.html new file mode 100644 index 00000000..08e27212 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errormodel.html @@ -0,0 +1,140 @@ + + + + + + + + nepi.resources.ns3.ns3errormodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3errormodel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseErrorModel(NS3Base): + _rtype = "abstract::ns3::ErrorModel" + + @property +
[docs] 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errorratemodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errorratemodel.html new file mode 100644 index 00000000..7a81fc4c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3errorratemodel.html @@ -0,0 +1,144 @@ + + + + + + + + nepi.resources.ns3.ns3errorratemodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3errorratemodel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseErrorRateModel(NS3Base): + _rtype = "abstract::ns3::ErrorRateModel" + + @property +
[docs] def node(self): + return self.phy.node +
+ @property +
[docs] 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3fdnetdevice.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3fdnetdevice.html new file mode 100644 index 00000000..d220680b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3fdnetdevice.html @@ -0,0 +1,149 @@ + + + + + + + + nepi.resources.ns3.ns3fdnetdevice — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3fdnetdevice

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
+@clsinit_copy
+
[docs]class NS3BaseFdNetDevice(NS3BaseNetDevice): + _rtype = "abstract::ns3::FdNetDevice" + + @property + def _rms_to_wait(self): + rms = set([self.node]) + 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) + + def _instantiate_object(self): + """ just validate that the simulator is in real time + mode, otherwise it is not going to work + """ + + mode = self.simulation.get("simulatorImplementationType") + if mode != "ns3::RealtimeSimulatorImpl": + msg = "The simulation must run in real time!!" + self.error(msg) + raise RuntimeError, msg + + super(NS3BaseFdNetDevice, self)._instantiate_object() + +
[docs] def recv_fd(self): + address = self.simulation.invoke(self.uuid, "recvFD") + return address +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3icmpv4l4protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3icmpv4l4protocol.html new file mode 100644 index 00000000..08b9cac6 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3icmpv4l4protocol.html @@ -0,0 +1,134 @@ + + + + + + + + nepi.resources.ns3.ns3icmpv4l4protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3icmpv4l4protocol

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseIcmpv4L4Protocol(NS3Base): + _rtype = "abstract::ns3::Icmpv4L4Protocol" + + @property +
[docs] 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 +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ipv4l3protocol.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ipv4l3protocol.html new file mode 100644 index 00000000..af335aaf --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3ipv4l3protocol.html @@ -0,0 +1,157 @@ + + + + + + + + nepi.resources.ns3.ns3ipv4l3protocol — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3ipv4l3protocol

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]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 +
[docs] 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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3mobilitymodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3mobilitymodel.html new file mode 100644 index 00000000..63b72b4b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3mobilitymodel.html @@ -0,0 +1,135 @@ + + + + + + + + nepi.resources.ns3.ns3mobilitymodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3mobilitymodel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]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
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3netdevice.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3netdevice.html new file mode 100644 index 00000000..51630fad --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3netdevice.html @@ -0,0 +1,313 @@ + + + + + + + + nepi.resources.ns3.ns3netdevice — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3netdevice

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]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 +
[docs] 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 +
[docs] 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 +
[docs] 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 +
[docs] 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 +
[docs] 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" + elif rtype == "ns3::FdNetDevice": + classname = "FdNetDeviceHelper" + + self._device_helper_uuid = self.simulation.create(classname) + + return self._device_helper_uuid +
+ @property + def _rms_to_wait(self): + rms = set([self.node, 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) + + # Verify that the device has a queue. If no queue is added a segfault + # error occurs + queue = self.queue +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3node.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3node.html new file mode 100644 index 00000000..af6fefa7 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3node.html @@ -0,0 +1,285 @@ + + + + + + + + nepi.resources.ns3.ns3node — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3node

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseNode(NS3Base): + _rtype = "abstract::ns3::Node" + + def __init__(self, ec, guid): + super(NS3BaseNode, self).__init__(ec, guid) + self._simulation = None + self._node_id = None + self._ipv4 = None + self._arp = None + self._mobility = None + self._devices = None + self._dceapplications = None + + @classmethod + def _register_attributes(cls): + enablestack = Attribute("enableStack", + "Install network stack in Node, including: ARP, " + "IP4, ICMP, UDP and TCP ", + type = Types.Bool, + default = False, + flags = Flags.Design) + + cls._register_attribute(enablestack) + + @property +
[docs] def simulation(self): + if not self._simulation: + from nepi.resources.ns3.ns3simulation import NS3Simulation + for guid in self.connections: + rm = self.ec.get_resource(guid) + if isinstance(rm, NS3Simulation): + self._simulation = rm + + if not self._simulation: + msg = "Node not connected to simulation" + self.error(msg) + raise RuntimeError, msg + + return self._simulation +
+ @property +
[docs] def ipv4(self): + if not self._ipv4: + from nepi.resources.ns3.ns3ipv4l3protocol import NS3BaseIpv4L3Protocol + ipv4s = self.get_connected(NS3BaseIpv4L3Protocol.get_rtype()) + if ipv4s: + self._ipv4 = ipv4s[0] + + return self._ipv4 +
+ @property +
[docs] def arp(self): + if not self._arp: + from nepi.resources.ns3.ns3arpl3protocol import NS3BaseArpL3Protocol + arps = self.get_connected(NS3BaseArpL3Protocol.get_rtype()) + if arps: + self._arp = arps[0] + + return self._arp +
+ @property +
[docs] def mobility(self): + if not self._mobility: + from nepi.resources.ns3.ns3mobilitymodel import NS3BaseMobilityModel + mobility = self.get_connected(NS3BaseMobilityModel.get_rtype()) + if mobility: + self._mobility = mobility[0] + + return self._mobility +
+ @property +
[docs] def devices(self): + if not self._devices: + 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 + + self._devices = devices + + return self._devices +
+ @property +
[docs] def node_id(self): + return self._node_id +
+ @property +
[docs] def dceapplications(self): + if not self._dceapplications: + from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication + self._dceapplications = self.get_connected(NS3BaseDceApplication.get_rtype()) + + return self._dceapplications +
+ @property + def _rms_to_wait(self): + rms = set([self.simulation]) + + if self.ipv4: + rms.add(self.ipv4) + + if self.arp: + rms.add(self.arp) + + if self.mobility: + rms.add(self.mobility) + + return rms + + def _configure_object(self): + if self.get("enableStack"): + uuid_stack_helper = self.simulation.create("InternetStackHelper") + self.simulation.invoke(uuid_stack_helper, "Install", self.uuid) + + # Retrieve IPV4 object + ipv4_uuid = self.simulation.invoke(self.uuid, "retrieveObject", + "ns3::Ipv4L3Protocol") + + # Add IPv4 RM to the node + ipv4 = self.ec.register_resource("ns3::Ipv4L3Protocol") + self.ec.register_connection(self.guid, ipv4) + ipv4rm = self.ec.get_resource(ipv4) + ipv4rm._uuid = ipv4_uuid + ipv4rm.set_started() + else: + ### node.AggregateObject(PacketSocketFactory()) + uuid_packet_socket_factory = self.simulation.create("PacketSocketFactory") + self.simulation.invoke(self.uuid, "AggregateObject", uuid_packet_socket_factory) + + self._node_id = self.simulation.invoke(self.uuid, "GetId") + + dceapplications = self.dceapplications + if dceapplications: + self._add_dce(dceapplications) + + def _connect_object(self): + if not self.get("enableStack"): + ipv4 = self.ipv4 + if ipv4: + self.simulation.invoke(self.uuid, "AggregateObject", ipv4.uuid) + self._connected.add(ipv4.uuid) + ipv4._connected.add(self.uuid) + + arp = self.arp + if arp: + self.simulation.invoke(self.uuid, "AggregateObject", arp.uuid) + self._connected.add(arp.uuid) + arp._connected.add(self.uuid) + + mobility = self.mobility + if mobility: + self.simulation.invoke(self.uuid, "AggregateObject", mobility.uuid) + self._connected.add(mobility.uuid) + mobility._connected.add(self.uuid) + + def _add_dce(self, dceapplications): + dceapp = dceapplications[0] + + container_uuid = self.simulation.create("NodeContainer") + self.simulation.invoke(container_uuid, "Add", self.uuid) + + dce_helper = self.simulation.dce_helper + + with dce_helper.dce_manager_lock: + dce_manager_uuid = dce_helper.dce_manager_uuid + + self.simulation.invoke(dce_manager_uuid, "Install", container_uuid) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3pipechanel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3pipechanel.html new file mode 100644 index 00000000..6ebc43de --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3pipechanel.html @@ -0,0 +1,171 @@ + + + + + + + + nepi.resources.ns3.ns3pipechanel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3pipechanel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
+import socket
+
+@clsinit_copy
+
[docs]class NS3BasePipeChannel(NS3Base): + """ Interconnects two FdNetDevices with a PIPE + """ + _rtype = "ns3::PipeChannel" + + def __init__(self, ec, guid): + super(NS3BasePipeChannel, self).__init__(ec, guid) + self._devices = None + + @property +
[docs] def devices(self): + if not self._devices: + from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice + devices = self.get_connected(NS3BaseFdNetDevice.get_rtype()) + if not devices or len(devices) != 2: + msg = "PipeChannel must be connected to exactly to two FdNetDevices" + self.error(msg) + raise RuntimeError, msg + + self._devices = devices + + return self._devices +
+ @property +
[docs] def node(self): + return self.devices[0].node +
+ @property + def _rms_to_wait(self): + rms = set(self.devices) + return rms + + def _instantiate_object(self): + """ The pipe channel does not really exists as an ns-3 object. + Do nothing. + """ + pass + + def _connect_object(self): + dev1 = self.devices[0] + dev2 = self.devices[1] + + if dev1.uuid not in self.connected and dev2.uuid not in self.connected: + (s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) + + dev1.send_fd(s0) + + self._connected.add(dev1.uuid) + dev1._connected.add(self.uuid) + + dev2.send_fd(s1) + + self._connected.add(dev2.uuid) + dev2._connected.add(self.uuid) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationdelaymodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationdelaymodel.html new file mode 100644 index 00000000..885465e0 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationdelaymodel.html @@ -0,0 +1,144 @@ + + + + + + + + nepi.resources.ns3.ns3propagationdelaymodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3propagationdelaymodel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BasePropagationDelayModel(NS3Base): + _rtype = "abstract::ns3::PropagationDelayModel" + + @property +
[docs] def simulation(self): + return self.channel.simulation +
+ @property +
[docs] 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationlossmodel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationlossmodel.html new file mode 100644 index 00000000..8ded8355 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3propagationlossmodel.html @@ -0,0 +1,144 @@ + + + + + + + + nepi.resources.ns3.ns3propagationlossmodel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3propagationlossmodel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BasePropagationLossModel(NS3Base): + _rtype = "ns3::PropagationLossModel" + + @property +
[docs] def simulation(self): + return self.channel.simulation +
+ @property +
[docs] 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3queue.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3queue.html new file mode 100644 index 00000000..b61b1174 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3queue.html @@ -0,0 +1,145 @@ + + + + + + + + nepi.resources.ns3.ns3queue — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3queue

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseQueue(NS3Base): + _rtype = "abstract::ns3::Queue" + + @property +
[docs] 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 +
[docs] 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) + device._connected.add(self.uuid) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3route.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3route.html new file mode 100644 index 00000000..0364fb10 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3route.html @@ -0,0 +1,183 @@ + + + + + + + + nepi.resources.ns3.ns3route — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3route

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]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 +
[docs] 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3server.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3server.html new file mode 100644 index 00000000..bd8e1598 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3server.html @@ -0,0 +1,349 @@ + + + + + + + + nepi.resources.ns3.ns3server — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3server

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
+
[docs]class NS3WrapperMessage: + CREATE = "CREATE" + FACTORY = "FACTORY" + INVOKE = "INVOKE" + SET = "SET" + GET = "GET" + FLUSH = "FLUSH" + START = "START" + STOP = "STOP" + SHUTDOWN = "SHUTDOWN" +
+
[docs]def handle_message(ns3_wrapper, msg_type, args, kwargs): + if msg_type == NS3WrapperMessage.SHUTDOWN: + ns3_wrapper.shutdown() + + return "BYEBYE" + + if msg_type == NS3WrapperMessage.STOP: + time = kwargs.get("time") + + ns3_wrapper.stop(time=time) + + return "STOPPED" + + if msg_type == NS3WrapperMessage.START: + ns3_wrapper.start() + + return "STARTED" + + if msg_type == NS3WrapperMessage.CREATE: + clazzname = args.pop(0) + + return ns3_wrapper.create(clazzname, *args) + + if msg_type == NS3WrapperMessage.FACTORY: + type_name = args.pop(0) + + return ns3_wrapper.factory(type_name, **kwargs) + + if msg_type == NS3WrapperMessage.INVOKE: + uuid = args.pop(0) + operation = args.pop(0) + + return ns3_wrapper.invoke(uuid, operation, *args, **kwargs) + + if msg_type == NS3WrapperMessage.GET: + uuid = args.pop(0) + name = args.pop(0) + + return ns3_wrapper.get(uuid, name) + + if msg_type == NS3WrapperMessage.SET: + uuid = args.pop(0) + name = args.pop(0) + value = args.pop(0) + + return ns3_wrapper.set(uuid, name, 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" +
+
[docs]def open_socket(socket_name): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(socket_name) + return sock +
+
[docs]def close_socket(sock): + try: + sock.close() + except: + pass +
+
[docs]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) +
+
[docs]def send_reply(conn, reply): + encoded = base64.b64encode(cPickle.dumps(reply)) + conn.send("%s\n" % encoded) +
+
[docs]def get_options(): + usage = ("usage: %prog -S <socket-name> -L <ns-log> -D <enable-dump> -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("-D", "--enable-dump", dest="enable_dump", + help = "Enable dumping the remote executed ns-3 commands to a script " + "in order to later reproduce and debug the experiment", + action = "store_true", + default = False) + + 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, + options.enable_dump) +
+
[docs]def run_server(socket_name, level = logging.INFO, ns_log = None, + enable_dump = False): + + # 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, enable_dump = enable_dump) + + ns3_wrapper.logger.info("STARTING...") + + # create unix socket to receive instructions + sock = open_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(30) + + try: + (msg_type, args, kwargs) = recv_msg(conn) + except socket.timeout, e: + # Ingore time-out + close_socket(conn) + continue + + if not msg_type: + # Ignore - connection lost + close_socket(conn) + continue + + 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) + close_socket(conn) + raise + + try: + send_reply(conn, reply) + except socket.error: + import traceback + err = traceback.format_exc() + ns3_wrapper.logger.error(err) + close_socket(conn) + raise + + close_socket(conn) + + close_socket(sock) + + ns3_wrapper.logger.info("EXITING...") +
+if __name__ == '__main__': + + (socket_name, verbose, ns_log, enable_dump) = 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, enable_dump) +
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3simulation.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3simulation.html new file mode 100644 index 00000000..49eaeec5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3simulation.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.ns3simulation — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3simulation

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+
[docs]class NS3Simulation(object): + @property +
[docs] def client(self): + return self._client +
+
[docs] def create(self, *args, **kwargs): + return self.client.create(*args, **kwargs) +
+
[docs] def factory(self, *args, **kwargs): + return self.client.factory(*args, **kwargs) +
+
[docs] def invoke(self, *args, **kwargs): + return self.client.invoke(*args, **kwargs) +
+
[docs] def ns3_set(self, *args, **kwargs): + return self.client.set(*args, **kwargs) +
+
[docs] def ns3_get(self, *args, **kwargs): + return self.client.get(*args, **kwargs) +
+
[docs] def flush(self, *args, **kwargs): + return self.client.flush(*args, **kwargs) +
+
[docs] def start(self, *args, **kwargs): + return self.client.start(*args, **kwargs) +
+
[docs] def stop(self, *args, **kwargs): + return self.client.stop(*args, **kwargs) +
+
[docs] def shutdown(self, *args, **kwargs): + return self.client.shutdown(*args, **kwargs) +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifichannel.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifichannel.html new file mode 100644 index 00000000..48b899fa --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifichannel.html @@ -0,0 +1,141 @@ + + + + + + + + nepi.resources.ns3.ns3wifichannel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3wifichannel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseWifiChannel(NS3Base): + _rtype = "abstract::ns3::WifiChannel" + + @property +
[docs] def simulation(self): + return self.phys[0].device.node.simulation +
+ @property +
[docs] 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 +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifimac.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifimac.html new file mode 100644 index 00000000..3cc758e8 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifimac.html @@ -0,0 +1,169 @@ + + + + + + + + nepi.resources.ns3.ns3wifimac — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3wifimac

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]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 +
[docs] def node(self): + return self.device.node +
+ @property +
[docs] 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifinetdevice.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifinetdevice.html new file mode 100644 index 00000000..9dc4d7c4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifinetdevice.html @@ -0,0 +1,144 @@ + + + + + + + + nepi.resources.ns3.ns3wifinetdevice — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3wifinetdevice

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseWifiNetDevice(NS3BaseNetDevice): + _rtype = "abstract::ns3::WifiNetDevice" + + @property + def _rms_to_wait(self): + rms = set([self.node]) + 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiphy.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiphy.html new file mode 100644 index 00000000..acff23b2 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiphy.html @@ -0,0 +1,178 @@ + + + + + + + + nepi.resources.ns3.ns3wifiphy — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3wifiphy

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]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 +
[docs] def node(self): + return self.device.node +
+ @property +
[docs] 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 +
[docs] 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiremotestationmanager.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiremotestationmanager.html new file mode 100644 index 00000000..edb85a3f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wifiremotestationmanager.html @@ -0,0 +1,145 @@ + + + + + + + + nepi.resources.ns3.ns3wifiremotestationmanager — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3wifiremotestationmanager

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
[docs]class NS3BaseWifiRemoteStationManager(NS3Base): + _rtype = "abstract::ns3::WifiRemoteStationManager" + + @property +
[docs] def node(self): + return self.device.node +
+ @property +
[docs] 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) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper.html new file mode 100644 index 00000000..6a5723b3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper.html @@ -0,0 +1,795 @@ + + + + + + + + nepi.resources.ns3.ns3wrapper — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3wrapper

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 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"
+
+
[docs]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) +
+
[docs]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 +
+
[docs]class NS3Wrapper(object): + def __init__(self, loglevel = logging.INFO, enable_dump = False): + super(NS3Wrapper, self).__init__() + # Thread used to run the simulation + self._simulation_thread = None + self._condition = None + + # True if Simulator::Run was invoked + self._started = False + + # holds reference to all C++ objects and variables in the simulation + self._objects = dict() + + # Logging + 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 + + # Object to dump instructions to reproduce and debug experiment + from ns3wrapper_debug import NS3WrapperDebuger + self._debuger = NS3WrapperDebuger(enabled = enable_dump) + + @property +
[docs] def debuger(self): + return self._debuger +
+ @property +
[docs] def ns3(self): + if not self._ns3: + # load ns-3 libraries and bindings + self._ns3 = load_ns3_module() + + return self._ns3 +
+ @property +
[docs] 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 +
[docs] def logger(self): + return self._logger +
+ @property +
[docs] def is_running(self): + return self.is_started and not self.ns3.Simulator.IsFinished() +
+ @property +
[docs] def is_started(self): + if not self._started: + now = self.ns3.Simulator.Now() + if not now.IsZero(): + self._started = True + + return self._started +
+ @property +
[docs] def is_finished(self): + return self.ns3.Simulator.IsFinished() +
+
[docs] def make_uuid(self): + return "uuid%s" % uuid.uuid4() +
+
[docs] def get_object(self, uuid): + return self._objects.get(uuid) +
+
[docs] def factory(self, type_name, **kwargs): + """ This method should be used to construct ns-3 objects + that have a TypeId and related introspection information """ + + if type_name not in self.allowed_types: + msg = "Type %s not supported" % (type_name) + self.logger.error(msg) + + uuid = self.make_uuid() + + ### DEBUG + self.logger.debug("FACTORY %s( %s )" % (type_name, str(kwargs))) + + ### DUMP + self.debuger.dump_factory(uuid, type_name, kwargs) + + factory = self.ns3.ObjectFactory() + factory.SetTypeId(type_name) + + for name, value in kwargs.iteritems(): + ns3_value = self._attr_from_string_to_ns3_value(type_name, name, value) + factory.Set(name, ns3_value) + + obj = factory.Create() + + self._objects[uuid] = obj + + ### DEBUG + self.logger.debug("RET FACTORY ( uuid %s ) %s = %s( %s )" % ( + str(uuid), str(obj), type_name, str(kwargs))) + + return uuid +
+
[docs] def create(self, clazzname, *args): + """ This method should be used to construct ns-3 objects that + do not have a TypeId (e.g. Values) """ + + if not hasattr(self.ns3, clazzname): + msg = "Type %s not supported" % (clazzname) + self.logger.error(msg) + + uuid = self.make_uuid() + + ### DEBUG + self.logger.debug("CREATE %s( %s )" % (clazzname, str(args))) + + ### DUMP + self.debuger.dump_create(uuid, clazzname, args) + + clazz = getattr(self.ns3, clazzname) + + # 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) + + self._objects[uuid] = obj + + ### DEBUG + self.logger.debug("RET CREATE ( uuid %s ) %s = %s( %s )" % (str(uuid), + str(obj), clazzname, str(args))) + + return uuid +
+
[docs] def invoke(self, uuid, operation, *args, **kwargs): + ### DEBUG + self.logger.debug("INVOKE %s -> %s( %s, %s ) " % ( + uuid, operation, str(args), str(kwargs))) + ######## + + result = None + newuuid = None + + if operation == "isRunning": + result = self.is_running + + elif operation == "isStarted": + result = self.is_started + + elif operation == "isFinished": + result = self.is_finished + + elif operation == "isAppRunning": + result = self._is_app_running(uuid) + + elif operation == "isAppStarted": + result = self._is_app_started(uuid) + + elif operation == "recvFD": + ### passFD operation binds to a different random socket + ### en every execution, so the socket name that could be + ### dumped to the debug script using dump_invoke is + ### not be valid accross debug executions. + result = self._recv_fd(uuid, *args, **kwargs) + + elif operation == "addStaticRoute": + result = self._add_static_route(uuid, *args) + + ### DUMP - result is static, so will be dumped as plain text + self.debuger.dump_invoke(result, uuid, operation, args, kwargs) + + elif operation == "retrieveObject": + result = self._retrieve_object(uuid, *args, **kwargs) + + ### DUMP - result is static, so will be dumped as plain text + self.debuger.dump_invoke(result, uuid, operation, args, kwargs) + + else: + newuuid = self.make_uuid() + + ### DUMP - result is a uuid that encoded an dynamically generated + ### object + self.debuger.dump_invoke(newuuid, uuid, operation, args, kwargs) + + if uuid.startswith(SINGLETON): + obj = self._singleton(uuid) + else: + obj = self.get_object(uuid) + + method = getattr(obj, operation) + + # 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) + + result = method(*realargs, **realkwargs) + + # If the result is an object (not a base value), + # then keep track of the object a return the object + # reference (newuuid) + if not (result is None or type(result) in [ + bool, float, long, str, int]): + self._objects[newuuid] = result + result = newuuid + + ### DEBUG + self.logger.debug("RET INVOKE %s%s = %s -> %s(%s, %s) " % ( + "(uuid %s) " % str(newuuid) if newuuid else "", str(result), uuid, + operation, str(args), str(kwargs))) + ######## + + return result +
+ def _set_attr(self, obj, name, ns3_value): + obj.SetAttribute(name, ns3_value) + +
[docs] def set(self, uuid, name, value): + ### DEBUG + self.logger.debug("SET %s %s %s" % (uuid, name, str(value))) + + ### DUMP + self.debuger.dump_set(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) + + ### DEBUG + self.logger.debug("RET SET %s = %s -> set(%s, %s)" % (str(value), uuid, name, + str(value))) + + return value +
+ def _get_attr(self, obj, name, ns3_value): + obj.GetAttribute(name, ns3_value) + +
[docs] def get(self, uuid, name): + ### DEBUG + self.logger.debug("GET %s %s" % (uuid, name)) + + ### DUMP + self.debuger.dump_get(uuid, name) + + obj = self.get_object(uuid) + type_name = obj.GetInstanceTypeId().GetName() + ns3_value = self._create_attr_ns3_value(type_name, name) + + event_executed = [False] + + if self.is_running: + # schedule the event in the Simulator + self._schedule_event(self._condition, event_executed, + self._get_attr, obj, name, ns3_value) + + if not event_executed[0]: + self._get_attr(obj, name, ns3_value) + + result = self._attr_from_ns3_value_to_string(type_name, name, ns3_value) + + ### DEBUG + self.logger.debug("RET GET %s = %s -> get(%s)" % (str(result), uuid, name)) + + return result +
+
[docs] def start(self): + ### DUMP + self.debuger.dump_start() + + # Launch the simulator thread and Start the + # simulator in that thread + self._condition = threading.Condition() + self._simulator_thread = threading.Thread( + target = self._simulator_run, + args = [self._condition]) + self._simulator_thread.setDaemon(True) + self._simulator_thread.start() + + ### DEBUG + self.logger.debug("START") +
+
[docs] def stop(self, time = None): + ### DUMP + self.debuger.dump_stop(time=time) + + if time is None: + self.ns3.Simulator.Stop() + else: + self.ns3.Simulator.Stop(self.ns3.Time(time)) + + ### DEBUG + self.logger.debug("STOP time=%s" % str(time)) +
+
[docs] def shutdown(self): + ### DUMP + self.debuger.dump_shutdown() + + while not self.ns3.Simulator.IsFinished(): + #self.logger.debug("Waiting for simulation to finish") + time.sleep(0.5) + + if self._simulator_thread: + self._simulator_thread.join() + + self.ns3.Simulator.Destroy() + + # Remove all references to ns-3 objects + self._objects.clear() + + sys.stdout.flush() + sys.stderr.flush() + + ### DEBUG + self.logger.debug("SHUTDOWN") +
+ def _simulator_run(self, condition): + # Run simulation + self.ns3.Simulator.Run() + # Signal condition to indicate simulation ended and + # notify waiting threads + condition.acquire() + condition.notifyAll() + condition.release() + + 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, event_executed, func, *args): + try: + func(*args) + event_executed[0] = True + finally: + # notify condition indicating event was executed + condition.acquire() + condition.notifyAll() + condition.release() + + # contextId is defined as general context + contextId = long(0xffffffff) + + # 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 + + condition.acquire() + try: + self.ns3.Simulator.ScheduleWithContext(contextId, delay, execute_event, + condition, event_executed, func, *args) + if not self.ns3.Simulator.IsFinished(): + condition.wait() + finally: + condition.release() + + def _create_attr_ns3_value(self, type_name, name): + TypeId = self.ns3.TypeId() + tid = TypeId.LookupByName(type_name) + info = TypeId.AttributeInformation() + if not tid.LookupAttributeByName(name, info): + 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 _attr_from_ns3_value_to_string(self, type_name, name, ns3_value): + TypeId = self.ns3.TypeId() + tid = TypeId.LookupByName(type_name) + info = TypeId.AttributeInformation() + if not tid.LookupAttributeByName(name, info): + msg = "TypeId %s has no attribute %s" % (type_name, name) + self.logger.error(msg) + + checker = info.checker + value = ns3_value.SerializeToString(checker) + + type_name = checker.GetValueTypeName() + if type_name in ["ns3::UintegerValue", "ns3::IntegerValue"]: + return int(value) + if type_name == "ns3::DoubleValue": + return float(value) + if type_name == "ns3::BooleanValue": + return value == "true" + + return value + + def _attr_from_string_to_ns3_value(self, type_name, name, value): + TypeId = self.ns3.TypeId() + tid = TypeId.LookupByName(type_name) + info = TypeId.AttributeInformation() + if not tid.LookupAttributeByName(name, info): + msg = "TypeId %s has no attribute %s" % (type_name, name) + self.logger.error(msg) + + str_value = str(value) + if isinstance(value, bool): + str_value = str_value.lower() + + checker = info.checker + ns3_value = checker.Create() + ns3_value.DeserializeFromString(str_value, checker) + return ns3_value + + # singletons are identified as "ns3::ClassName" + def _singleton(self, ident): + if not ident.startswith(SINGLETON): + return None + + clazzname = ident[ident.find("::")+2:] + if not hasattr(self.ns3, clazzname): + msg = "Type %s not supported" % (clazzname) + self.logger.error(msg) + + return getattr(self.ns3, clazzname) + + # replace uuids and singleton references for the real objects +
[docs] 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
+
[docs] 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 + + if self.ns3.Simulator.IsFinished(): + 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: + if stop_time.IsZero() or now.Compare(stop_time) < 0: + return True + + return False + + def _is_app_started(self, uuid): + return self._is_app_running(uuid) or self.is_finished + + 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 + + def _retrieve_object(self, uuid, typeid, search = False): + obj = self.get_object(uuid) + + type_id = self.ns3.TypeId() + tid = type_id.LookupByName(typeid) + nobj = obj.GetObject(tid) + + newuuid = None + if search: + # search object + for ouuid, oobj in self._objects.iteritems(): + if nobj == oobj: + newuuid = ouuid + break + else: + newuuid = self.make_uuid() + self._objects[newuuid] = nobj + + return newuuid + + def _recv_fd(self, uuid): + """ Waits on a local address to receive a file descriptor + from a local process. The file descriptor is associated + to a FdNetDevice to stablish communication between the + simulation and what ever process writes on that file descriptor + """ + + def recvfd(sock, fdnd): + (fd, msg) = passfd.recvfd(sock) + # Store a reference to the endpoint to keep the socket alive + fdnd.SetFileDescriptor(fd) + + import passfd + import socket + sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + sock.bind("") + address = sock.getsockname() + + fdnd = self.get_object(uuid) + t = threading.Thread(target=recvfd, args=(sock,fdnd)) + t.start() + + return address +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper_debug.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper_debug.html new file mode 100644 index 00000000..fe27b391 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/ns3wrapper_debug.html @@ -0,0 +1,271 @@ + + + + + + + + nepi.resources.ns3.ns3wrapper_debug — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.ns3wrapper_debug

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+
+############ METHODS DEBUG NS3WRAPPER EXECUTION
+##
+## The ns3wrapper works in ditributed mode, receiving instructions from
+## a remote client. This makes it very hard to debug scripting errors 
+## in the client side. To simplify error debugging, when set to debug mode,
+## the ns3wrapper dumps every executed line to a script that can be then
+## executed locally to reproduce and debug the experiment.
+##
+###########################################################################
+
+import logging
+
+SINGLETON = "singleton::"
+
+
[docs]class NS3WrapperDebuger(object): + def __init__(self, enabled): + super(NS3WrapperDebuger, self).__init__() + self._enabled = enabled + self._script_path = "debug.py" + + self.dump_header() + + @property +
[docs] def enabled(self): + return self._enabled +
+ @property +
[docs] def script_path(self): + return self._script_path +
+
[docs] def dump_to_script(self, command): + f = open(self.script_path, "a") + f.write("%s" % command) + f.close() +
+
[docs] def dump_header(self): + if not self.enabled: + return + + header = """ +from ns3wrapper import NS3Wrapper + +wrapper = NS3Wrapper() + +""" + self.dump_to_script(header) +
+
[docs] def dump_factory(self, uuid, type_name, kwargs): + if not self.enabled: + return + + command = ("kwargs = %(kwargs)s\n" + "%(uuid)s = wrapper.factory(%(type_name)s, **kwargs)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "type_name": self.format_value(type_name), + "kwargs": self.format_kwargs(kwargs) + }) + + self.dump_to_script(command) +
+
[docs] def dump_create(self, uuid, clazzname, args): + if not self.enabled: + return + + command = ("args = %(args)s\n" + "%(uuid)s = wrapper.create(%(clazzname)s, *args)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "clazzname": self.format_value(clazzname), + "args": self.format_args(args), + }) + + self.dump_to_script(command) +
+
[docs] def dump_invoke(self, newuuid, uuid, operation, args, kwargs): + if not self.enabled: + return + + command = ("args = %(args)s\n" + "kwargs = %(kwargs)s\n" + "%(newuuid)s = wrapper.invoke(%(uuid)s, %(operation)s, *args, **kwargs)\n\n" + ) % dict({ + "newuuid": self.format_value(newuuid) if newuuid else "nothing", + "uuid": self.format_value(uuid), + "operation": self.format_value(operation), + "args": self.format_args(args), + "kwargs": self.format_kwargs(kwargs), + }) + + self.dump_to_script(command) +
+
[docs] def dump_set(self, uuid, name, value): + if not self.enabled: + return + + command = ("wrapper.set(%(uuid)s, %(name)s, %(value)s)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "name": self.format_value(name), + "value": self.format_value(value), + }) + + self.dump_to_script(command) +
+
[docs] def dump_get(self, uuid, name): + if not self.enabled: + return + + command = ("wrapper.get(%(uuid)s, %(name)s)\n\n" + ) % dict({ + "uuid": self.format_value(uuid), + "name": self.format_value(name), + }) + + self.dump_to_script(command) +
+
[docs] def dump_start(self): + if not self.enabled: + return + + command = "wrapper.start()\n\n" + self.dump_to_script(command) +
+
[docs] def dump_stop(self, time = None): + if not self.enabled: + return + + command = ("wrapper.stop(time=%(time)s)\n\n" + ) % dict({ + "time": self.format_value(time) if time else "None", + }) + + self.dump_to_script(command) +
+
[docs] def dump_shutdown(self): + if not self.enabled: + return + + command = "wrapper.shutdown()\n\n" + self.dump_to_script(command) +
+
[docs] def format_value(self, value): + if isinstance(value, str) and value.startswith("uuid"): + return value.replace("-", "") + + import pprint + return pprint.pformat(value) +
+
[docs] def format_args(self, args): + fargs = map(self.format_value, args) + return "[%s]" % ",".join(fargs) +
+
[docs] def format_kwargs(self, kwargs): + fkwargs = map(lambda (k,w): + "%s: %s" % (self.format_value(k), self.format_value(w)), + kwargs.iteritems()) + + return "dict({%s})" % ",".join(fkwargs) +
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/ns3/resource_manager_generator.html b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/resource_manager_generator.html new file mode 100644 index 00000000..b47fabae --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/ns3/resource_manager_generator.html @@ -0,0 +1,330 @@ + + + + + + + + nepi.resources.ns3.resource_manager_generator — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.ns3.resource_manager_generator

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+#
+# Instructions to automatically generate ns-3 ResourceManagers
+# 
+# Configure the ns-3 enviorment (e.g.):
+#
+#  export PYTHONPATH=~/.nepi/nepi-usr/bin/ns-3/ns-3.20/optimized/build/lib/python/site-packages
+#  export LD_LIBRARY_PATH=~/.nepi/nepi-usr/bin/ns-3/ns-3.20/optimized/build/lib
+#
+# Run the RM generator:
+#
+#  PYTHONPATH=$PYTHONPATH:~/repos/nepi/src python src/nepi/resources/ns3/resource_manager_generator.py
+#
+
+# Force the load of ns3 libraries
+from nepi.resources.ns3.ns3wrapper import load_ns3_module
+
+import os
+import re
+
+adapted_types = ["ns3::Node",
+        "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",
+        "ns3::Application", 
+        "ns3::FdNetDevice",
+        #"ns3::DceApplication", 
+        "ns3::NetDevice",
+        "ns3::Channel",
+        "ns3::Queue"]
+
+base_types = ["ns3::IpL4Protocol"]
+
+
[docs]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) +
+
[docs]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() +
+
[docs]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 +
+
[docs]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() +
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/application.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/application.html new file mode 100644 index 00000000..d5e68655 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/application.html @@ -0,0 +1,510 @@ + + + + + + + + nepi.resources.omf.application — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.application

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+import os
+
+from nepi.util.timefuncs import tnow
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.execution.trace import Trace, TraceAttr
+from nepi.execution.attribute import Attribute, Flags 
+from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
+from nepi.resources.omf.node import OMFNode, confirmation_counter, reschedule_check
+from nepi.resources.omf.omf_api_factory import OMFAPIFactory
+
+from nepi.util import sshfuncs
+
+@clsinit_copy
+
[docs]class OMFApplication(OMFResource): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + _rtype = "omf::Application" + _authorized_connections = ["omf::Node", "wilabt::sfa::Node"] + + @classmethod + def _register_attributes(cls): + """ Register the attributes of an OMF application + + """ + command = Attribute("command", "Command to execute") + env = Attribute("env", "Environnement variable of the application") + + # For OMF 5: + appid = Attribute("appid", "Name of the application") + stdin = Attribute("stdin", "Input of the application", default = "") + sources = Attribute("sources", "Sources of the application", + flags = Flags.Design) + sshuser = Attribute("sshUser", "user to connect with ssh", + flags = Flags.Design) + sshkey = Attribute("sshKey", "key to use for ssh", + flags = Flags.Design) + + cls._register_attribute(appid) + cls._register_attribute(command) + cls._register_attribute(env) + cls._register_attribute(stdin) + cls._register_attribute(sources) + cls._register_attribute(sshuser) + cls._register_attribute(sshkey) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + :param creds: Credentials to communicate with the rm (XmppClient for OMF) + :type creds: dict + + """ + super(OMFApplication, self).__init__(ec, guid) + + self.set('command', "") + self.set('appid', "") + self._path= "" + self._args = "" + self.set('env', "") + + self._node = None + + self._omf_api = None + self._topic_app = None + self.create_id = None + self._create_cnt = 0 + self._start_cnt = 0 + self.release_id = None + self._release_cnt = 0 + + # For performance tests + self.begin_deploy_time = None + self.begin_start_time = None + self.begin_release_time = None + self.dperf = True + self.sperf = True + self.rperf = True + + self.add_set_hook() + + def _init_command(self): + comm = self.get('command').split(' ') + self._path= comm[0] + if len(comm)>1: + self._args = ' '.join(comm[1:]) + + @property +
[docs] def exp_id(self): + return self.ec.exp_id +
+ @property +
[docs] def node(self): + rm_list = self.get_connected(OMFNode.get_rtype()) + if rm_list: return rm_list[0] + return None +
+
[docs] def stdin_hook(self, old_value, new_value): + """ Set a hook to the stdin attribute in order to send a message at each time + the value of this parameter is changed. Used ofr OMF 5.4 only + + """ + self._omf_api.send_stdin(self.node.get('hostname'), new_value, self.get('appid')) + return new_value +
+
[docs] def add_set_hook(self): + """ Initialize the hooks for OMF 5.4 only + + """ + attr = self._attrs["stdin"] + attr.set_hook = self.stdin_hook +
+
[docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. + Only meaningful connections are allowed. + + :param guid: Guid of RM it will be connected + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() not in self._authorized_connections: + msg = ("Connection between %s %s and %s %s refused: " + "An Application can be connected only to a Node" ) % \ + (self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + + return False + + elif len(self.connections) != 0 : + msg = ("Connection between %s %s and %s %s refused: " + "This Application is already connected" ) % \ + (self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + + return False + + else : + msg = "Connection between %s %s and %s %s accepted" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + + return True +
+
[docs] def do_deploy(self): + """ Deploy the RM. It means nothing special for an application + for now (later it will be upload sources, ...) + It becomes DEPLOYED after the topic for the application has been created + + """ + if not self.node or self.node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " + % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + return + + ## For performance test + if self.dperf: + self.begin_deploy_time = tnow() + self.dperf = False + + self._init_command() + + self.set('xmppUser',self.node.get('xmppUser')) + self.set('xmppServer',self.node.get('xmppServer')) + self.set('xmppPort',self.node.get('xmppPort')) + self.set('xmppPassword',self.node.get('xmppPassword')) + self.set('version',self.node.get('version')) + + if not self.get('xmppServer'): + msg = "XmppServer is not initialzed. XMPP Connections impossible" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('xmppUser') or self.get('xmppPort') + or self.get('xmppPassword')): + msg = "Credentials are not all initialzed. Default values will be used" + self.warn(msg) + + if not self.get('command') : + msg = "Application's Command is not initialized" + self.error(msg) + raise RuntimeError, msg + + if not self._omf_api : + self._omf_api = OMFAPIFactory.get_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + if self.get('version') == "5": + + self.begin_deploy_time = tnow() + + if self.get('sources'): + gateway = ResourceGateway.AMtoGateway[self.get('xmppServer')] + user = self.get('sshUser') or self.get('xmppUser') + dst = user + "@"+ gateway + ":" + (out, err), proc = sshfuncs.rcopy(self.get('sources'), dst) + else : + # For OMF 6 : + if not self.create_id: + props = {} + if self.get('command'): + props['application:binary_path'] = self.get('command') + props['application:hrn'] = self.get('command') + props['application:membership'] = self._topic_app + props['application:type'] = "application" + + self.create_id = os.urandom(16).encode('hex') + self._omf_api.frcp_create( self.create_id, self.node.get('hostname'), "application", props = props) + + if self._create_cnt > confirmation_counter: + msg = "Couldn't retrieve the confirmation of the creation" + self.error(msg) + raise RuntimeError, msg + + uid = self.check_deploy(self.create_id) + if not uid: + self._create_cnt +=1 + self.ec.schedule(reschedule_check, self.deploy) + return + + self._topic_app = uid + self._omf_api.enroll_topic(self._topic_app) + + super(OMFApplication, self).do_deploy() +
+
[docs] def check_deploy(self, cid): + """ Check, through the mail box in the parser, + if the confirmation of the creation has been received + + :param cid: the id of the original message + :type guid: string + + """ + uid = self._omf_api.check_mailbox("create", cid) + if uid : + return uid + return False +
+
[docs] def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0): + self.info("Retrieving '%s' trace %s " % (name, attr)) + if name == 'stdout' : + suffix = '.out' + elif name == 'stderr' : + suffix = '.err' + else : + suffix = '.misc' + + trace_path = '/tmp/'+ self._topic_app + suffix + + if attr == TraceAttr.PATH: + return trace_path + + if attr == TraceAttr.ALL: + try: + f = open(trace_path ,'r') + except IOError: + print "File with traces has not been found" + return False + out = f.read() + f.close() + return out + +
+
[docs] def do_start(self): + """ Start the RM. It means : Send Xmpp Message Using OMF protocol + to execute the application. + + """ + ## For performance test + if self.sperf: + self.begin_start_time = tnow() + self.sperf = False + + if not self.get('env'): + self.set('env', " ") + + if self.get('version') == "5": + self.begin_start_time = tnow() + # Some information to check the command for OMF5 + msg = " " + self.get_rtype() + " ( Guid : " + str(self._guid) +") : " + \ + self.get('appid') + " : " + self._path + " : " + \ + self._args + " : " + self.get('env') + self.debug(msg) + + self._omf_api.execute(self.node.get('hostname'),self.get('appid'), \ + self._args, self._path, self.get('env')) + else: + #For OMF 6 + if self._start_cnt == 0: + props = {} + props['state'] = "running" + + guards = {} + guards['type'] = "application" + guards['name'] = self.get('command') + + self._omf_api.frcp_configure(self._topic_app, props = props, guards = guards ) + + if self._start_cnt > confirmation_counter: + msg = "Couldn't retrieve the confirmation that the application started" + self.error(msg) + raise RuntimeError, msg + + res = self.check_start(self._topic_app) + if not res: + self._start_cnt +=1 + self.ec.schedule(reschedule_check, self.start) + return + + super(OMFApplication, self).do_start() +
+
[docs] def check_start(self, uid): + """ Check, through the mail box in the parser, + if the confirmation of the start has been received + + :param uid: the id of the original message + :type guid: string + + """ + res = self._omf_api.check_mailbox("started", uid) + if res : + return True + return False +
+
[docs] def do_stop(self): + """ Stop the RM. It means : Send Xmpp Message Using OMF protocol to + kill the application. + State is set to STOPPED after the message is sent. + + """ + + + if self.get('version') == 5: + self._omf_api.exit(self.node.get('hostname'),self.get('appid')) + super(OMFApplication, self).do_stop() +
+
[docs] def check_release(self, cid): + """ Check, through the mail box in the parser, + if the confirmation of the release has been received + + :param cid: the id of the original message + :type guid: string + + """ + res = self._omf_api.check_mailbox("release", cid) + if res : + return res + return False +
+
[docs] def do_release(self): + """ Clean the RM at the end of the experiment and release the API. + + """ + ## For performance test + if self.rperf: + self.begin_release_time = tnow() + self.rperf = False + + if self._omf_api: + if self.get('version') == "6" and self._topic_app: + if not self.release_id: + self.release_id = os.urandom(16).encode('hex') + self._omf_api.frcp_release( self.release_id, self.node.get('hostname'),self._topic_app, res_id=self._topic_app) + + if self._release_cnt < confirmation_counter: + cid = self.check_release(self.release_id) + if not cid: + self._release_cnt +=1 + self.ec.schedule(reschedule_check, self.release) + return + else: + msg = "Couldn't retrieve the confirmation of the release" + self.error(msg) + + # Remove the stdout and stderr of the application + try: + os.remove('/tmp/'+self._topic_app +'.out') + os.remove('/tmp/'+self._topic_app +'.err') + except OSError: + pass + + OMFAPIFactory.release_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + super(OMFApplication, self).do_release() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/channel.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/channel.html new file mode 100644 index 00000000..6ee1dc46 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/channel.html @@ -0,0 +1,291 @@ + + + + + + + + nepi.resources.omf.channel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.channel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+from nepi.util.timefuncs import tnow
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.execution.attribute import Attribute, Flags 
+
+from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
+from nepi.resources.omf.omf_api_factory import OMFAPIFactory
+
+
+@clsinit_copy
+
[docs]class OMFChannel(OMFResource): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + :param creds: Credentials to communicate with the rm (XmppClient for OMF) + :type creds: dict + + """ + _rtype = "omf::Channel" + _authorized_connections = ["omf::WifiInterface", "omf::Node"] + + ChannelToFreq = dict({ + "1" : "2412", + "2" : "2417", + "3" : "2422", + "4" : "2427", + "5" : "2432", + "6" : "2437", + "7" : "2442", + "8" : "2447", + "9" : "2452", + "10" : "2457", + "11" : "2462", + "12" : "2467", + "13" : "2472", + }) + + @classmethod + def _register_attributes(cls): + """Register the attributes of an OMF channel + + """ + channel = Attribute("channel", "Name of the application") + cls._register_attribute(channel) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + super(OMFChannel, self).__init__(ec, guid) + + self._nodes_guid = list() + self.frequency = None + + self._omf_api = None + + # For performance tests + self.perf = True + self.begin_deploy_time = None + + + @property +
[docs] def exp_id(self): + return self.ec.exp_id +
+
[docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. + Only meaningful connections are allowed. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() in self._authorized_connections: + msg = "Connection between %s %s and %s %s accepted" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return True + msg = "Connection between %s %s and %s %s refused" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return False +
+ def _get_target(self, conn_set): + """ + Get the couples (host, interface) that uses this channel + + :param conn_set: Connections of the current Guid + :type conn_set: set + :rtype: list + :return: self._nodes_guid + + """ + res = [] + for elt in conn_set: + rm_iface = self.ec.get_resource(elt) + for conn in rm_iface.connections: + rm_node = self.ec.get_resource(conn) + if rm_node.get_rtype() == "omf::Node" and rm_node.get('hostname'): + if rm_iface.state < ResourceState.PROVISIONED or \ + rm_node.state < ResourceState.READY: + return "reschedule" + couple = [rm_node.get('hostname'), rm_iface.alias] + res.append(couple) + return res + +
[docs] def get_frequency(self, channel): + """ Returns the frequency of a specific channel number + + """ + return OMFChannel.ChannelToFreq[channel] +
+
[docs] def do_deploy(self): + """ Deploy the RM. It means : Get the xmpp client and send messages + using OMF 5.4 or 6 protocol to configure the channel. + + """ + + ## For performance test + if self.perf: + self.begin_deploy_time = tnow() + self.perf = False + + if not self.get('channel'): + msg = "Channel's value is not initialized" + self.error(msg) + raise RuntimeError, msg + + if self.get('version') == "6": + self.frequency = self.get_frequency(self.get('channel')) + super(OMFChannel, self).do_deploy() + return + + if not self.get('xmppServer'): + msg = "XmppServer is not initialzed. XMPP Connections impossible" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('xmppUser') or self.get('xmppPort') + or self.get('xmppPassword')): + msg = "Credentials are not all initialzed. Default values will be used" + self.warn(msg) + + if not self._omf_api : + self._omf_api = OMFAPIFactory.get_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + self._nodes_guid = self._get_target(self._connections) + + if self._nodes_guid == "reschedule" : + self.ec.schedule("1s", self.deploy) + else: + for couple in self._nodes_guid: + attrval = self.get('channel') + attrname = "net/%s/%s" % (couple[1], 'channel') + self._omf_api.configure(couple[0], attrname, attrval) + + super(OMFChannel, self).do_deploy() +
+
[docs] def do_release(self): + """ Clean the RM at the end of the experiment and release the API + + """ + if self._omf_api : + OMFAPIFactory.release_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + super(OMFChannel, self).do_release() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/interface.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/interface.html new file mode 100644 index 00000000..2d6f044c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/interface.html @@ -0,0 +1,430 @@ + + + + + + + + nepi.resources.omf.interface — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.interface

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+import os, time
+from nepi.util.timefuncs import tnow
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.execution.attribute import Attribute, Flags 
+
+from nepi.resources.omf.node import OMFNode, confirmation_counter, reschedule_check
+from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
+from nepi.resources.omf.channel import OMFChannel
+from nepi.resources.omf.omf_api_factory import OMFAPIFactory
+
+@clsinit_copy
+
[docs]class OMFWifiInterface(OMFResource): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + _rtype = "omf::WifiInterface" + _authorized_connections = ["omf::Node" , "omf::Channel", "wilabt::sfa::Node"] + + @classmethod + def _register_attributes(cls): + """Register the attributes of an OMF interface + + """ + name = Attribute("name","Alias of the interface : wlan0, wlan1, ..", default = "wlan0") + mode = Attribute("mode","Mode of the interface") + hw_mode = Attribute("hw_mode","Choose between : a, b, g, n") + essid = Attribute("essid","Essid of the interface") + ip = Attribute("ip","IP of the interface") + cls._register_attribute(name) + cls._register_attribute(mode) + cls._register_attribute(hw_mode) + cls._register_attribute(essid) + cls._register_attribute(ip) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + :param creds: Credentials to communicate with the rm (XmppClient for OMF) + :type creds: dict + + """ + super(OMFWifiInterface, self).__init__(ec, guid) + + self._conf = False + self.alias = None + self._type = None + + self.create_id = None + self._create_cnt = 0 + self.release_id = None + self._release_cnt = 0 + self._topic_iface = None + self._omf_api = None + self._type = "" + + # For performance tests + self.perf = True + self.begin_deploy_time = None + +
[docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. + Only meaningful connections are allowed. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() in self._authorized_connections: + msg = "Connection between %s %s and %s %s accepted" % \ + (self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return True + + msg = "Connection between %s %s and %s %s refused" % \ + (self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return False +
+ @property +
[docs] def exp_id(self): + return self.ec.exp_id +
+ @property +
[docs] def node(self): + rm_list = self.get_connected(OMFNode.get_rtype()) + if rm_list: return rm_list[0] + return None +
+ @property +
[docs] def channel(self): + rm_list = self.get_connected(OMFChannel.get_rtype()) + if rm_list: return rm_list[0] + return None +
+
[docs] def configure_iface(self): + """ Configure the interface without the ip + + """ + if self.node.state < ResourceState.READY: + self.ec.schedule(self.reschedule_delay, self.deploy) + return False + + for attrname in ["mode", "type", "essid"]: + if attrname == "type" : + attrval = self._type + else : + attrval = self.get(attrname) + attrname = "net/%s/%s" % (self.alias, attrname) + self._omf_api.configure(self.node.get('hostname'), attrname, + attrval) + + super(OMFWifiInterface, self).do_provision() + return True +
+
[docs] def configure_ip(self): + """ Configure the ip of the interface + + .. note : The ip is separated from the others parameters to avoid + CELL ID shraing problem. By putting th ip at the end of the configuration, + each node use the same channel and can then share the same CELL ID. + In the second case, the channel is defined at the end and the node don't + share a common CELL ID and can not communicate. + + """ + if self.channel.state < ResourceState.READY: + self.ec.schedule(self.reschedule_delay, self.deploy) + return False + + attrval = self.get("ip") + if '/' in attrval: + attrval,mask = attrval.split('/') + attrname = "net/%s/%s" % (self.alias, "ip") + self._omf_api.configure(self.node.get('hostname'), attrname, + attrval) + return True + +
+
[docs] def configure_on_omf5(self): + """ Method to configure the wifi interface when OMF 5.4 is used. + + """ + + self._type = self.get('hw_mode') + if self.get('name') == "wlan0" or "eth0": + self.alias = "w0" + else: + self.alias = "w1" + res = False + if self.state < ResourceState.PROVISIONED: + if self._conf == False: + self._conf = self.configure_iface() + if self._conf == True: + res = self.configure_ip() + return res +
+
[docs] def check_deploy(self, cid): + """ Check, through the mail box in the parser, + if the confirmation of the creation has been received + + :param cid: the id of the original message + :type guid: string + + """ + uid = self._omf_api.check_mailbox("create", cid) + if uid : + return uid + return False +
+
[docs] def do_deploy(self): + """ Deploy the RM. It means : Get the xmpp client and send messages + using OMF 5.4 or 6 protocol to configure the interface. + + """ + if not self.node or self.node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " + % self.node.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + return + + if not self.channel or self.channel.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- channel state %s " + % self.channel.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + return + + ## For performance test + if self.perf: + self.begin_deploy_time = tnow() + self.perf = False + + self.set('xmppUser',self.node.get('xmppUser')) + self.set('xmppServer',self.node.get('xmppServer')) + self.set('xmppPort',self.node.get('xmppPort')) + self.set('xmppPassword',self.node.get('xmppPassword')) + self.set('version',self.node.get('version')) + + if not self.get('xmppServer'): + msg = "XmppServer is not initialzed. XMPP Connections impossible" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('xmppUser') or self.get('xmppPort') + or self.get('xmppPassword')): + msg = "Credentials are not all initialzed. Default values will be used" + self.warn(msg) + + if not self._omf_api : + self._omf_api = OMFAPIFactory.get_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + if not (self.get('name')): + msg = "Interface's name is not initialized" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('mode') and self.get('essid') \ + and self.get('hw_mode') and self.get('ip')): + msg = "Interface's variable are not initialized" + self.error(msg) + raise RuntimeError, msg + + if self.get('version') == "5": + res = self.configure_on_omf5() + + else : + res = self.configure_on_omf6() + + if res: + super(OMFWifiInterface, self).do_deploy() +
+
[docs] def configure_on_omf6(self): + """ Method to configure the wifi interface when OMF 6 is used. + + """ + if not self.create_id : + props = {} + props['wlan:if_name'] = self.get('name') + props['wlan:mode'] = { + "mode": self.get('mode'), + "hw_mode" : self.get('hw_mode'), + "channel" : self.channel.get('channel'), + "essid" : self.get('essid'), + "ip_addr" : self.get('ip'), + "frequency" : self.channel.frequency, + "phy" : "%0%" + } + props['wlan:hrn'] = self.get('name') + props['wlan:type'] = "wlan" + + self.create_id = os.urandom(16).encode('hex') + self._omf_api.frcp_create( self.create_id, self.node.get('hostname'), "wlan", props = props) + + if self._create_cnt > confirmation_counter: + msg = "Couldn't retrieve the confirmation of the creation" + self.error(msg) + raise RuntimeError, msg + + uid = self.check_deploy(self.create_id) + if not uid: + self._create_cnt +=1 + self.ec.schedule(reschedule_check, self.deploy) + return False + + self._topic_iface = uid + self._omf_api.enroll_topic(self._topic_iface) + return True +
+
[docs] def check_release(self, cid): + """ Check, through the mail box in the parser, + if the confirmation of the release has been received + + :param cid: the id of the original message + :type guid: string + + """ + res = self._omf_api.check_mailbox("release", cid) + if res : + return res + return False +
+
[docs] def do_release(self): + """ Clean the RM at the end of the experiment and release the API + + """ + if self._omf_api: + if self.get('version') == "6" and self._topic_iface : + if not self.release_id: + self.release_id = os.urandom(16).encode('hex') + self._omf_api.frcp_release( self.release_id, self.node.get('hostname'),self._topic_iface, res_id=self._topic_iface) + + if self._release_cnt < confirmation_counter: + cid = self.check_release(self.release_id) + if not cid: + self._release_cnt +=1 + self.ec.schedule(reschedule_check, self.release) + return + else: + msg = "Couldn't retrieve the confirmation of the release" + self.error(msg) + + + OMFAPIFactory.release_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + super(OMFWifiInterface, self).do_release() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_5_4.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_5_4.html new file mode 100644 index 00000000..96c65136 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_5_4.html @@ -0,0 +1,345 @@ + + + + + + + + nepi.resources.omf.messages_5_4 — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.messages_5_4

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+from xml.etree import cElementTree as ET
+
+
[docs]class MessageHandler(): + """ + .. class:: Class Args : + + :param sliceid: Slice Name (= Xmpp Slice) + :type expid: str + :param expid: Experiment ID (= Xmpp User) + :type expid: str + + .. note:: + + This class is used only for OMF 5.4 Protocol and is going to become unused + + """ + + def __init__(self, sliceid, expid ): + """ + + :param sliceid: Slice Name (= Xmpp Slice) + :type expid: str + :param expid: Experiment ID (= Xmpp User) + :type expid: str + + """ + self._slice_id = sliceid + self._exp_id = expid + + + def _id_element(self, parent, markup): + """ Insert a markup element with an id + + :param parent: Parent element in an XML point of view + :type parent: ElementTree Element + :param markup: Name of the markup + :type markup: str + + """ + elt = ET.SubElement(parent, markup) + elt.set("id", "\'omf-payload\'") + return elt + + def _attr_element(self, parent, markup, text): + """ Insert a markup element with a text (value) + + :param parent: Parent element in an XML point of view + :type parent: ElementTree Element + :param markup: Name of the markup + :type markup: str + :param text: Value of the markup element + :type text: str + + """ + elt = ET.SubElement(parent, markup) + elt.text = text + return elt + +
[docs] def execute_function(self, target, appid, cmdlineargs, path, env): + """ Build an Execute Message + + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + :param appid: Application id + :type appid: str + :param cmdlineargs: Arguments of the application + :type cmdlineargs: str + :param path: Path of the application + :type path: str + :param env: Environment variables + :type env: str + + """ + payload = ET.Element("omf-message") + execute = self._id_element(payload,"EXECUTE") + env = self._attr_element(execute, "ENV", env) + sliceid = self._attr_element(execute,"SLICEID",self._slice_id) + expid = self._attr_element(execute,"EXPID",self._exp_id) + target = self._attr_element(execute,"TARGET",target) + appid = self._attr_element(execute,"APPID",appid) + cmdlineargs = self._attr_element(execute,"CMDLINEARGS",cmdlineargs) + path = self._attr_element(execute,"PATH",path) + return payload +
+
[docs] def stdin_function(self, target, value, appid): + """ Build an Execute Message + + :param value: parameter that go in the stdin + :type value: str + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + :param appid: Application id + :type appid: str + + """ + payload = ET.Element("omf-message") + stdin = self._id_element(payload,"STDIN") + value = self._attr_element(stdin,"VALUE",value) + sliceid = self._attr_element(stdin,"SLICEID",self._slice_id) + expid = self._attr_element(stdin,"EXPID",self._exp_id) + target = self._attr_element(stdin,"TARGET",target) + appid = self._attr_element(stdin,"APPID",appid) + return payload +
+
[docs] def exit_function(self, target, appid): + """ Build an Exit Message + + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + :param appid: Application id (ex : vlc#1) + :type appid: str + + """ + payload = ET.Element("omf-message") + execute = self._id_element(payload,"EXIT") + sliceid = self._attr_element(execute,"SLICEID",self._slice_id) + expid = self._attr_element(execute,"EXPID",self._exp_id) + target = self._attr_element(execute,"TARGET",target) + appid = self._attr_element(execute,"APPID",appid) + return payload +
+
[docs] def configure_function(self, target, value, path): + """ Build a Configure Message + + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + :param value: guid of the RM + :type value: int + :param path: Path of the element to configure (ex : net/w0/channel) + :type path: dict + + """ + payload = ET.Element("omf-message") + config = self._id_element(payload, "CONFIGURE") + sliceid = self._attr_element(config,"SLICEID",self._slice_id) + expid = self._attr_element(config,"EXPID",self._exp_id) + target = self._attr_element(config,"TARGET",target) + value = self._attr_element(config,"VALUE",value) + path = self._attr_element(config,"PATH",path) + return payload +
+
[docs] def log_function(self,level, logger, level_name, data): + """ Build a Log Message + + :param level: Level of logging + :type level: str + :param logger: Element publishing the log + :type logger: str + :param level_name: Name of the level (ex : INFO) + :type level_name: str + :param data: Content to publish + :type data: str + + """ + payload = ET.Element("omf-message") + log = self._id_element(payload, "LOGGING") + level = self._attr_element(log,"LEVEL",level) + sliceid = self._attr_element(log,"SLICEID",self._slice_id) + logger = self._attr_element(log,"LOGGER",logger) + expid = self._attr_element(log,"EXPID",self._exp_id) + level_name = self._attr_element(log,"LEVEL_NAME",level_name) + data = self._attr_element(log,"DATA",data) + return payload +
+
[docs] def alias_function(self, name, target): + """ Build an Alias Message + + :param name: Name of the new alias + :type name: str + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + + """ + payload = ET.Element("omf-message") + alias = self._id_element(payload,"ALIAS") + sliceid = self._attr_element(alias,"SLICEID",self._slice_id) + expid = self._attr_element(alias,"EXPID",self._exp_id) + name = self._attr_element(alias,"NAME",name) + target = self._attr_element(alias,"TARGET",target) + return payload +
+
[docs] def enroll_function(self, enrollkey, image, index, target ): + """ Build an Enroll Message + + :param enrollkey: Type of enrollment (= 1) + :type enrollkey: str + :param image: Image (= * when all the nodes are concerned) + :type image: str + :param index: Index (= 1 in general) + :type index: str + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + + """ + payload = ET.Element("omf-message") + enroll = self._id_element(payload,"ENROLL") + enrollkey = self._attr_element(enroll,"ENROLLKEY",enrollkey) + sliceid = self._attr_element(enroll,"SLICEID",self._slice_id) + image = self._attr_element(enroll,"IMAGE",image) + expid = self._attr_element(enroll,"EXPID",self._exp_id) + index = self._attr_element(enroll,"INDEX",index) + target = self._attr_element(enroll,"TARGET",target) + return payload +
+
[docs] def noop_function(self,target): + """ Build a Noop Message + + :param target: Hrn of the target node (ex : omf.plexus.wlab17) + :type target: str + + """ + payload = ET.Element("omf-message") + noop = self._id_element(payload,"NOOP") + sliceid = self._attr_element(noop,"SLICEID",self._slice_id) + expid = self._attr_element(noop,"EXPID",self._exp_id) + target = self._attr_element(noop,"TARGET",target) + return payload +
+
[docs] def newexp_function(self, experimentid, address): + """ Build a NewExp Message + + :param experimentid: Id of the new experiment + :type experimentid: str + :param address: Adress of the destination set of nodes + :type address: str + + """ + payload = ET.Element("omf-message") + newexp = self._id_element(payload,"EXPERIMENT_NEW") + experimentid = self._attr_element(newexp,"EXPERIMENT_ID",experimentid) + sliceid = self._attr_element(newexp,"SLICEID",self._slice_id) + expid = self._attr_element(newexp,"EXPID",self._exp_id) + address = self._attr_element(newexp,"ADDRESS",address) + return payload +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_6.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_6.html new file mode 100644 index 00000000..6e54de86 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/messages_6.html @@ -0,0 +1,343 @@ + + + + + + + + nepi.resources.omf.messages_6 — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.messages_6

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+from xml.etree import cElementTree as ET
+
+
[docs]class MessageHandler(): + """ + .. class:: Class Args : + + :param sliceid: Slice Name (= Xmpp Slice) + :type expid: str + :param expid: Experiment ID (= Xmpp User) + :type expid: str + + .. note:: + + This class is used only for OMF 5.4 Protocol and is going to become unused + + """ + + def __init__(self): + """ + + """ + pass + + def _type_element(self, type_elt, xmlns, msg_id): + """ Insert a markup element with an id + + """ + elt = ET.Element(type_elt) + elt.set("xmlns", xmlns) + elt.set("mid", msg_id) + return elt + + + + def _attr_element(self, parent, markup, text, type_key=None, type_value = None): + """ Insert a markup element with a text (value) + + :param parent: Parent element in an XML point of view + :type parent: ElementTree Element + :param markup: Name of the markup + :type markup: str + :param text: Value of the markup element + :type text: str + + """ + elt = ET.SubElement(parent, markup) + if type_key and type_value: + elt.set(type_key, type_value) + elt.text = text + return elt + + def _id_element(self, parent, markup, key, value): + """ Insert a markup element with a text (value) + + :param parent: Parent element in an XML point of view + :type parent: ElementTree Element + :param markup: Name of the markup + :type markup: str + :param text: Value of the markup element + :type text: str + + """ + elt = ET.SubElement(parent, markup) + elt.set(key, value) + return elt + +
[docs] def create_function(self, msg_id, src, rtype, timestamp, props = None, guards = None): + """ Build a create message + + :param msg_id: Id of the message + :type msg_id: str + :param src: Src node that send the message (jabber source) + :type src: str + :param rtype: Type of the object + :type rtype: str + :param timestamp: Unix Timestamp + :type timestamp: str + :param props: List of properties + :type props: list + :param guards: list of guards (assertions for properties) + :type guards: list + """ + payload = self._type_element("create", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) + self._attr_element(payload,"src",src) + self._attr_element(payload,"ts",timestamp) + self._attr_element(payload,"rtype",rtype) + + if props : + if rtype == "application" : + properties = self._id_element(payload,"props","xmlns:application", + "http://schema.mytestbed.net/omf/6.0/protocol/application") + elif rtype == "wlan" : + properties = self._id_element(payload,"props","xmlns:wlan", + "http://schema.mytestbed.net/omf/6.0/protocol/wlan") + else: + properties = self._attr_element(payload,"props","") + + for prop in props.keys(): + if isinstance(props[prop],str): + self._attr_element(properties,prop,props[prop],type_key="type", type_value = "string") + elif isinstance(props[prop],dict): + key = self._attr_element(properties,prop,"",type_key="type", type_value = "hash") + for comp in props[prop].keys(): + self._attr_element(key,comp,props[prop][comp],type_key="type", type_value = "string") + + if guards : + guardians = self._attr_element(payload,"guard","") + for guard in guards.keys(): + self._attr_element(guardians,guard,guards[guard],type_key="type", type_value = "string") + + return payload +
+
[docs] def configure_function(self, msg_id, src, timestamp, props = None, guards = None): + """ Build a configure message + + :param msg_id: Id of the message + :type msg_id: str + :param src: Src node that send the message (jabber source) + :type src: str + :param timestamp: Unix Timestamp + :type timestamp: str + :param props: List of properties + :type props: list + :param guards: list of guards (assertions for properties) + :type guards: list + """ + payload = self._type_element("configure", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) + self._attr_element(payload,"src",src) + self._attr_element(payload,"ts",timestamp) + + if props : + properties = self._attr_element(payload,"props","") + for prop in props.keys(): + self._attr_element(properties,prop,props[prop],type_key="type", type_value = "symbol") + + if guards : + guardians = self._attr_element(payload,"guard","") + for guard in guards.keys(): + self._attr_element(guardians,guard,guards[guard],type_key="type", type_value = "string") + + return payload +
+
[docs] def request_function(self, msg_id, src, timestamp, props = None, guards = None): + """ Build a request message + + :param msg_id: Id of the message + :type msg_id: str + :param src: Src node that send the message (jabber source) + :type src: str + :param timestamp: Unix Timestamp + :type timestamp: str + :param props: List of properties + :type props: list + :param guards: list of guards (assertions for properties) + :type guards: list + """ + payload = self._type_element("request", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) + self._attr_element(payload,"src",src) + self._attr_element(payload,"ts",timestamp) + + if props : + properties = self._attr_element(payload,"props","") + for prop in props.keys(): + self._attr_element(properties,prop,props[prop]) + + if guards : + guardians = self._attr_element(payload,"guard","") + for guard in guards.keys(): + self._attr_element(guardians,guard,guards[guard]) + return payload + +# For now, we don't need the inform message since it is ht RC that send them. + +# def inform_function(self, msg_id, src, timestamp, cid, itype): +# """ Build an inform message + +# :param msg_id: Id of the message +# :type msg_id: str +# :param src: Src node that send the message (jabber source) +# :type src: str +# :param rtype: Type of the object +# :type rtype: str +# :param timestamp: Unix Timestamp +# :type timestamp: str +# :param cid: Id of the orignial message +# :type cid: str +# :param itype: type of the object created +# :type itype: str +# """ + +# payload = self._type_element("inform", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) +# sliceid = self._attr_element(payload,"src",src) +# expid = self._attr_element(config,"ts",timestamp) +# target = self._attr_element(config,"cid",cid) +# value = self._attr_element(config,"itype",value) +# path = self._attr_element(config,"properties",path) +# return payload +
+
[docs] def release_function(self, msg_id, src, timestamp, res_id = None, props = None, guards = None): + """ Build a release message + + :param msg_id: Id of the message + :type msg_id: str + :param src: Src node that send the message (jabber source) + :type src: str + :param timestamp: Unix Timestamp + :type timestamp: str + :param res_id: Id of the release resource + :type res_id: str + :param props: List of properties + :type props: list + :param guards: list of guards (assertions for properties) + :type guards: list + """ + payload = self._type_element("release", "http://schema.mytestbed.net/omf/6.0/protocol", msg_id ) + self._attr_element(payload,"src",src) + self._attr_element(payload,"ts",timestamp) + if res_id : + self._attr_element(payload,"res_id",res_id) + + if props : + properties = self._id_element(payload,"props","xmlns:frcp", + "http://schema.mytestbed.net/omf/6.0/protocol") + for prop in props.keys(): + self._attr_element(properties,prop,props[prop]) + + if guards : + guardians = self._attr_element(payload,"guard","") + for guard in guards.keys(): + self._attr_element(guardians,guard,guards[guard]) + + return payload +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/node.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/node.html new file mode 100644 index 00000000..8648767c --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/node.html @@ -0,0 +1,267 @@ + + + + + + + + nepi.resources.omf.node — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.node

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+from nepi.util.timefuncs import tnow
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.execution.attribute import Attribute, Flags 
+from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
+from nepi.resources.omf.omf_api_factory import OMFAPIFactory
+
+import time
+
+reschedule_check = "1s"
+confirmation_counter = 3600
+
+@clsinit_copy
+
[docs]class OMFNode(OMFResource): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + :param creds: Credentials to communicate with the rm (XmppClient for OMF) + :type creds: dict + + """ + _rtype = "omf::Node" + _authorized_connections = ["omf::Application" , "omf::WifiInterface"] + + @classmethod + def _register_attributes(cls): + """Register the attributes of an OMF Node + + """ + hostname = Attribute("hostname", "Hostname of the machine") + + cls._register_attribute(hostname) + + # XXX: We don't necessary need to have the credentials at the + # moment we create the RM + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + super(OMFNode, self).__init__(ec, guid) + + self._omf_api = None + + # For performance tests + self.perf = True + self.begin_deploy_time = None + + + @property +
[docs] def exp_id(self): + return self.ec.exp_id +
+
[docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. + Only meaningful connections are allowed. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() in self._authorized_connections: + msg = "Connection between %s %s and %s %s accepted" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) + return True + + msg = "Connection between %s %s and %s %s refused" % ( + self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.error(msg) + + return False +
+
[docs] def do_deploy(self): + """ Deploy the RM. It means : Send Xmpp Message Using OMF protocol + to enroll the node into the experiment. + + """ + ## For performance test + if self.perf: + self.begin_deploy_time = tnow() + self.perf = False + + if not self.get('xmppServer'): + msg = "XmppServer is not initialzed. XMPP Connections impossible" + self.error(msg) + raise RuntimeError, msg + + if not self.get('version'): + msg = "Version of OMF is not indicated" + self.error(msg) + raise RuntimeError, msg + + if not (self.get('xmppUser') or self.get('xmppPort') + or self.get('xmppPassword')): + msg = "Credentials are not all initialzed. Default values will be used" + self.warn(msg) + + if not self._omf_api : + self._omf_api = OMFAPIFactory.get_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + if not self.get('hostname') : + msg = "Hostname's value is not initialized" + self.error(msg) + raise RuntimeError, msg + + if self.get('version') == "5": + self._omf_api.enroll_host(self.get('hostname')) + else: + self._omf_api.enroll_topic(self.get('hostname')) + + super(OMFNode, self).do_deploy() +
+
[docs] def do_release(self): + """ Clean the RM at the end of the experiment by unenrolling + the node from the topic + + """ + from nepi.resources.omf.application import OMFApplication + rm_list = self.get_connected(OMFApplication.get_rtype()) + if rm_list: + for rm in rm_list: + if rm.state < ResourceState.RELEASED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + from nepi.resources.omf.interface import OMFWifiInterface + rm_list = self.get_connected(OMFWifiInterface.get_rtype()) + if rm_list: + for rm in rm_list: + if rm.state < ResourceState.RELEASED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + if self._omf_api: + if self.get('version') == "5": + self._omf_api.release(self.get('hostname')) + else: + self._omf_api.unenroll_topic(self.get('hostname')) + + OMFAPIFactory.release_api(self.get('version'), + self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'), + self.get('xmppPassword'), exp_id = self.exp_id) + + super(OMFNode, self).do_release() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf5_api.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf5_api.html new file mode 100644 index 00000000..fae34e80 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf5_api.html @@ -0,0 +1,402 @@ + + + + + + + + nepi.resources.omf.omf5_api — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.omf5_api

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+import ssl
+import sys
+import time
+
+from nepi.util.logger import Logger
+
+from nepi.resources.omf.omf_client import OMFClient
+from nepi.resources.omf.messages_5_4 import MessageHandler
+
+
[docs]class OMF5API(Logger): + """ + .. class:: Class Args : + + :param host: Xmpp Server + :type host: str + :param slice: Xmpp Slice + :type slice: str + :param port: Xmpp Port + :type port: str + :param password: Xmpp password + :type password: str + :param xmpp_root: Root of the Xmpp Topic Architecture + :type xmpp_root: str + + .. note:: + + This class is the implementation of an OMF 5.4 API. + Since the version 5.4.1, the Topic Architecture start with OMF_5.4 + instead of OMF used for OMF5.3 + + """ + def __init__(self, host, slice, port, password, xmpp_root = None, + exp_id = None): + """ + :param host: Xmpp Server + :type host: str + :param slice: Xmpp Slice + :type slice: str + :param port: Xmpp Port + :type port: str + :param password: Xmpp password + :type password: str + :param xmpp_root: Root of the Xmpp Topic Architecture + :type xmpp_root: str + + """ + super(OMF5API, self).__init__("OMF5API") + self._exp_id = exp_id + self._user = "%s-%s" % (slice, self._exp_id) + self._slice = slice + self._host = host + self._port = port + self._password = password + self._hostnames = [] + self._xmpp_root = xmpp_root or "OMF_5.4" + + # OMF xmpp client + self._client = None + + # message handler + self._message = None + + if sys.version_info < (3, 0): + reload(sys) + sys.setdefaultencoding('utf8') + + # instantiate the xmpp client + self._init_client() + + # register xmpp nodes for the experiment + self._enroll_experiment() + self._enroll_newexperiment() + + # register xmpp logger for the experiment + self._enroll_logger() + + def _init_client(self): + """ Initialize XMPP Client + + """ + jid = "%s@%s" % (self._user, self._host) + xmpp = OMFClient(jid, self._password) + # PROTOCOL_SSLv3 required for compatibility with OpenFire + xmpp.ssl_version = ssl.PROTOCOL_SSLv3 + + if xmpp.connect((self._host, self._port)): + xmpp.process(block=False) + while not xmpp.ready: + time.sleep(1) + self._client = xmpp + self._message = MessageHandler(self._slice, self._user) + else: + msg = "Unable to connect to the XMPP server." + self.error(msg) + raise RuntimeError(msg) + + def _enroll_experiment(self): + """ Create and Subscribe to the Session Topic + + """ + xmpp_node = self._exp_session_id + self._client.create(xmpp_node) + #print "Create experiment sesion id topics !!" + self._client.subscribe(xmpp_node) + #print "Subscribe to experiment sesion id topics !!" + + + def _enroll_newexperiment(self): + """ Publish New Experiment Message + + """ + address = "/%s/%s/%s/%s" % (self._host, self._xmpp_root, self._slice, + self._user) + #print address + payload = self._message.newexp_function(self._user, address) + slice_sid = "/%s/%s" % (self._xmpp_root, self._slice) + self._client.publish(payload, slice_sid) + + def _enroll_logger(self): + """ Create and Subscribe to the Logger Topic + + """ + xmpp_node = self._logger_session_id + self._client.create(xmpp_node) + self._client.subscribe(xmpp_node) + + payload = self._message.log_function("2", + "nodeHandler::NodeHandler", + "INFO", + "OMF Experiment Controller 5.4 (git 529a626)") + self._client.publish(payload, xmpp_node) + + def _host_session_id(self, hostname): + """ Return the Topic Name as /xmpp_root/slice/user/hostname + + :param hostname: Full hrn of the node + :type hostname: str + + """ + return "/%s/%s/%s/%s" % (self._xmpp_root, self._slice, self._user, + hostname) + + def _host_resource_id(self, hostname): + """ Return the Topic Name as /xmpp_root/slice/resources/hostname + + :param hostname: Full hrn of the node + :type hostname: str + + """ + return "/%s/%s/resources/%s" % (self._xmpp_root, self._slice, hostname) + + @property + def _exp_session_id(self): + """ Return the Topic Name as /xmpp_root/slice/user + + """ + return "/%s/%s/%s" % (self._xmpp_root, self._slice, self._user) + + @property + def _logger_session_id(self): + """ Return the Topic Name as /xmpp_root/slice/LOGGER + + """ + return "/%s/%s/%s/LOGGER" % (self._xmpp_root, self._slice, self._user) + +
[docs] def delete(self, hostname): + """ Delete the topic corresponding to the hostname for this session + + :param hostname: Full hrn of the node + :type hostname: str + + """ + if not hostname in self._hostnames: + return + + self._hostnames.remove(hostname) + + xmpp_node = self._host_session_id(hostname) + self._client.delete(xmpp_node) +
+
[docs] def enroll_host(self, hostname): + """ Create and Subscribe to the session topic and the resources + corresponding to the hostname + + :param hostname: Full hrn of the node + :type hostname: str + + """ + if hostname in self._hostnames: + return + + self._hostnames.append(hostname) + + xmpp_node = self._host_session_id(hostname) + self._client.create(xmpp_node) + self._client.subscribe(xmpp_node) + + xmpp_node = self._host_resource_id(hostname) + self._client.subscribe(xmpp_node) + + payload = self._message.enroll_function("1", "*", "1", hostname) + self._client.publish(payload, xmpp_node) +
+
[docs] def configure(self, hostname, attribute, value): + """ Configure attribute on the node + + :param hostname: Full hrn of the node + :type hostname: str + :param attribute: Attribute that need to be configured ( + often written as /net/wX/attribute, with X the interface number) + :type attribute: str + :param value: Value of the attribute + :type value: str + + """ + payload = self._message.configure_function(hostname, value, attribute) + xmpp_node = self._host_session_id(hostname) + self._client.publish(payload, xmpp_node) + +
+
[docs] def send_stdin(self, hostname, value, app_id): + """ Send to the stdin of the application the value + + :param hostname: Full hrn of the node + :type hostname: str + :param appid: Application Id (Any id that represents in a unique + way the application) + :type appid: str + :param value: parameter to execute in the stdin of the application + :type value: str + + """ + payload = self._message.stdin_function(hostname, value, app_id) + xmpp_node = self._host_session_id(hostname) + self._client.publish(payload, xmpp_node) + +
+
[docs] def execute(self, hostname, app_id, arguments, path, env): + """ Execute command on the node + + :param hostname: Full hrn of the node + :type hostname: str + :param app_id: Application Id (Any id that represents in a unique + way the application) + :type app_id: str + :param arguments: Arguments of the application + :type arguments: str + :param path: Path of the application + :type path: str + :param env: Environnement values for the application + :type env: str + + """ + payload = self._message.execute_function(hostname, app_id, arguments, + path, env) + xmpp_node = self._host_session_id(hostname) + self._client.publish(payload, xmpp_node) +
+
[docs] def exit(self, hostname, app_id): + """ Kill an application started with OMF + + :param hostname: Full hrn of the node + :type hostname: str + :param app_id: Application Id of the application you want to stop + :type app_id: str + + """ + payload = self._message.exit_function(hostname, app_id) + xmpp_node = self._host_session_id(hostname) + self._client.publish(payload, xmpp_node) +
+
[docs] def release(self, hostname): + """ Delete the session and logger topics. Then disconnect + + """ + if hostname in self._hostnames: + self.delete(hostname) +
+
[docs] def disconnect(self) : + """ Delete the session and logger topics. Then disconnect + + """ + self._client.delete(self._exp_session_id) + self._client.delete(self._logger_session_id) + + time.sleep(1) + + # Wait the send queue to be empty before disconnect + self._client.disconnect(wait=True) + msg = " Disconnected from XMPP Server" + self.debug(msg) +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_api.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_api.html new file mode 100644 index 00000000..4e069bfa --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_api.html @@ -0,0 +1,351 @@ + + + + + + + + nepi.resources.omf.omf6_api — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.omf6_api

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+import ssl
+import sys
+import time
+
+from nepi.util.timefuncs import tsformat 
+import os
+
+from nepi.util.logger import Logger
+
+from nepi.resources.omf.omf_client import OMFClient
+from nepi.resources.omf.messages_6 import MessageHandler
+
+
[docs]class OMF6API(Logger): + """ + .. class:: Class Args : + + :param server: Xmpp Server + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port + :type port: str + :param password: Xmpp password + :type password: str + :param xmpp_root: Root of the Xmpp Topic Architecture + :type xmpp_root: str + + .. note:: + + This class is the implementation of an OMF 5.4 API. + Since the version 5.4.1, the Topic Architecture start with OMF_5.4 + instead of OMF used for OMF5.3 + + """ + def __init__(self, server, user = "nepi", port="5222", password="1234", + exp_id = None): + """ + :param server: Xmpp Server + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port + :type port: str + :param password: Xmpp password + :type password: str + :param xmpp_root: Root of the Xmpp Topic Architecture + :type xmpp_root: str + + """ + super(OMF6API, self).__init__("OMF6API") + self._exp_id = exp_id + self._user = user # name of the machine that run Nepi + self._server = server # name of the xmpp server + self._port = port # port of the xmpp server + self._password = password # password to connect to xmpp + self._jid = "%s-%s@%s" % (self._user, self._exp_id, self._server) + self._src = "xmpp://" + self._jid + + self._topics = [] + + # OMF xmpp client + self._client = None + + # message handler + self._message = None + + if sys.version_info < (3, 0): + reload(sys) + sys.setdefaultencoding('utf8') + + # instantiate the xmpp client + self._init_client() + + # register nepi topic + self._enroll_nepi() + + + def _init_client(self): + """ Initialize XMPP Client + + """ + xmpp = OMFClient(self._jid, self._password) + # PROTOCOL_SSLv3 required for compatibility with OpenFire + xmpp.ssl_version = ssl.PROTOCOL_SSLv3 + + if xmpp.connect((self._server, self._port)): + xmpp.process(block=False) + self.check_ready(xmpp) + self._client = xmpp + self._message = MessageHandler() + else: + msg = "Unable to connect to the XMPP server." + self.error(msg) + raise RuntimeError(msg) + +
[docs] def check_ready(self, xmpp): + delay = 1.0 + for i in xrange(15): + if xmpp.ready: + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = "XMPP Client is not ready after long time" + self.error(msg) + raise RuntimeError, msg +
+ @property + def _nepi_topic(self): + """ Return the name of the session topic + + """ + msg = "nepi-" + self._exp_id + self.debug(msg) + return msg + + def _enroll_nepi(self): + """ Create and Subscribe to the session Topic + + """ + nepi_topic = self._nepi_topic + self._client.create(nepi_topic) + self._client.subscribe(nepi_topic) + + +
[docs] def create_and_enroll_topic(self, topic): + """ Create and Subscribe to the session topic and the resources + corresponding to the hostname + + :param hostname: Full hrn of the node + :type hostname: str + + """ + if topic in self._topics: + return + + self._topics.append(topic) + + self._client.create(topic) + self._client.subscribe(topic) + +
+
[docs] def enroll_topic(self, topic): + """ Create and Subscribe to the session topic and the resources + corresponding to the hostname + + """ + if topic in self._topics: + return + + self._topics.append(topic) + self._client.subscribe(topic) + +
+
[docs] def frcp_inform(self, topic, cid, itype): + """ Publish an inform message + + """ + msg_id = os.urandom(16).encode('hex') + timestamp = tsformat() + payload = self._message.inform_function(msg_id, self._src, timestamp, props = props ,guards = guards) + + self._client.publish(payload, xmpp_node) +
+
[docs] def frcp_configure(self, topic, props = None, guards = None ): + """ Publish a configure message + + """ + msg_id = os.urandom(16).encode('hex') + timestamp = tsformat() + payload = self._message.configure_function(msg_id, self._src, timestamp ,props = props ,guards = guards) + self._client.publish(payload, topic) + +
+
[docs] def frcp_create(self, msg_id, topic, rtype, props = None, guards = None ): + """ Publish a create message + + """ + timestamp = tsformat() + payload = self._message.create_function(msg_id, self._src, rtype, timestamp , props = props ,guards = guards) + self._client.publish(payload, topic) + +
+
[docs] def frcp_request(self, topic, props = None, guards = None ): + """ Execute command on the node + + """ + msg_id = os.urandom(16).encode('hex') + timestamp = tsformat() + payload = self._message.request_function(msg_id, self._src, timestamp, props = props ,guards = guards) + self._client.publish(payload, xmpp_node) +
+
[docs] def frcp_release(self, msg_id, parent, child, res_id = None, props = None, guards = None ): + """ Publish a release message + + """ + timestamp = tsformat() + payload = self._message.release_function(msg_id, self._src, timestamp, res_id = res_id, props = props ,guards = guards) + self._client.publish(payload, parent) + + if child in self._topics: + self._topics.remove(child) + + self._client.unsubscribe(child) + #self._client.delete(child) +
+
[docs] def check_mailbox(self, itype, attr): + """ Check the mail box + + :param itype: type of mail + :type itype: str + :param attr: value wanted + :type attr: str + + """ + return self._client.check_mailbox(itype, attr) +
+
[docs] def unenroll_topic(self, topic): + """ Create and Subscribe to the session topic and the resources + corresponding to the hostname + + """ + if topic in self._topics: + self._topics.remove(topic) + self._client.unsubscribe(topic) +
+
[docs] def disconnect(self) : + """ Delete the session and logger topics. Then disconnect + + """ + # To receive the last messages + time.sleep(2) + + self._client.delete(self._nepi_topic) + + # Wait the send queue to be empty before disconnect + self._client.disconnect(wait=True) + msg = " Disconnected from XMPP Server" + self.debug(msg) +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_parser.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_parser.html new file mode 100644 index 00000000..4f79178b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf6_parser.html @@ -0,0 +1,382 @@ + + + + + + + + nepi.resources.omf.omf6_parser — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.omf6_parser

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+from nepi.util.logger import Logger
+
+import os
+import traceback
+import xml.etree.ElementTree as ET
+
+# inherit from BaseXmpp and XMLstream classes
+
[docs]class OMF6Parser(Logger): + """ + .. class:: Class Args : + + :param jid: Jabber Id (= Xmpp Slice + Date) + :type jid: str + :param password: Jabber Password (= Xmpp Password) + :type password: str + + .. note:: + + This class is an XMPP Client with customized method + + """ + + def __init__(self): + """ + + :param jid: Jabber Id (= Xmpp Slice + Date) + :type jid: str + :param password: Jabber Password (= Xmpp Password) + :type password: str + + + """ + super(OMF6Parser, self).__init__("OMF6API") + self.mailbox={} + self.traces={} + self.trace='NULL' + + self.init_mailbox() + + +
[docs] def init_mailbox(self): + self.mailbox['create'] = [] + self.mailbox['started'] = [] + self.mailbox['release'] = [] +
+ def _check_for_tag(self, root, namespaces, tag): + """ Check if an element markup is in the ElementTree + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the element + :type namespaces: str + :param tag: Tag that will search in the tree + :type tag: str + + """ + for element in root.iter(namespaces+tag): + if element.text: + return element.text + else : + return None + + def _check_for_props(self, root, namespaces): + """ Check if an element markup is in the ElementTree + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the element + :type namespaces: str + + """ + props = {} + for properties in root.iter(namespaces+'props'): + for element in properties.iter(): + if element.tag and element.text: + props[element.tag] = element.text + return props + + def _check_for_membership(self, root, namespaces): + """ Check if an element markup is in the ElementTree + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the element + :type namespaces: str + + """ + for element in root.iter(namespaces+'membership'): + for elt in element.iter(namespaces+'it'): + ##XXX : change + return elt.text + + + def _check_output(self, root, namespaces): + """ Check the significative element in the answer and display it + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the tree + :type namespaces: str + + """ + fields = ["TARGET", "REASON", "PATH", "APPID", "VALUE"] + response = "" + for elt in fields: + msg = self._check_for_tag(root, namespaces, elt) + if msg is not None: + response = response + " " + msg.text + " :" + deb = self._check_for_tag(root, namespaces, "MESSAGE") + if deb is not None: + msg = response + " " + deb.text + self.debug(msg) + else : + self.info(response) + + + def _inform_creation_ok(self, root, namespaces): + """ Parse and Display CREATION OK message + + """ + #ET.dump(root) + uid = self._check_for_tag(root, namespaces, "uid") + cid = self._check_for_tag(root, namespaces, "cid") + member = self._check_for_membership(root, namespaces) + binary_path = self._check_for_tag(root, namespaces, "binary_path") + msg = "CREATION OK -- " + if binary_path : + msg = msg + "The resource : '"+binary_path + else : + msg = msg + "The interface" + if uid : + msg = msg + "' is listening to the topics : '"+ uid + if member : + msg = msg + "' and '"+ member +"'" + if cid: + self.info(msg) + self.mailbox['create'].append([cid, uid ]) + + def _inform_creation_failed(self, root, namespaces): + """ Parse and Display CREATION FAILED message + + """ + reason = self._check_for_tag(root, namespaces, "reason") + cid = self._check_for_tag(root, namespaces, "cid") + msg = "CREATION FAILED - The reason : "+reason + if cid: + self.error(msg) + self.mailbox['create'].append([cid, uid ]) + + def _inform_status(self, root, namespaces): + """ Parse and Display STATUS message + + """ + props = self._check_for_props(root, namespaces) + uid = self._check_for_tag(root, namespaces, "uid") + event = self._check_for_tag(root, namespaces, "event") + + log = "STATUS -- " + for elt in props.keys(): + ns, tag = elt.split('}') + if tag == "it": + log = log + "membership : " + props[elt]+" -- " + elif tag == "event": + self.mailbox['started'].append(uid) + log = log + "event : " + props[elt]+" -- " + elif tag == "msg": + if event == "STDOUT" : + filename = os.path.join("/tmp", "%s.out" % uid) + f = open(filename,'a+') + # XXX: Adding fake \n for visual formatting + msg = props[elt] # + "\n" + f.write(msg) + f.close() + elif event == "STDERR" : + filename = os.path.join("/tmp", "%s.err" % uid) + f = open(filename,'a+') + # XXX: Adding fake \n for visual formatting + msg = props[elt] # + "\n" + f.write(msg) + f.close() + log = log + tag +" : " + props[elt]+" -- " + else: + log = log + tag +" : " + props[elt]+" -- " + log = log + " STATUS " + self.info(log) + + def _inform_released(self, root, namespaces): + """ Parse and Display RELEASED message + + """ + #ET.dump(root) + parent_id = self._check_for_tag(root, namespaces, "src") + child_id = self._check_for_tag(root, namespaces, "res_id") + cid = self._check_for_tag(root, namespaces, "cid") + if cid : + msg = "RELEASED - The resource : '"+child_id+ \ + "' has been released by : '"+ parent_id + self.info(msg) + self.mailbox['release'].append(cid) + + def _inform_error(self, root, namespaces): + """ Parse and Display ERROR message + + """ + reason = self._check_for_tag(root, namespaces, "reason") + msg = "The reason : "+reason + self.error(msg) + + def _inform_warn(self, root, namespaces): + """ Parse and Display WARN message + + """ + reason = self._check_for_tag(root, namespaces, "reason") + msg = "The reason : "+reason + self.warn(msg) + + def _parse_inform(self, root, namespaces): + """ Check the significative element in the answer + Then Parse it and display using specific method + + :param root: Root of the tree + :type root: ElementTree Element + :param namespaces: Namespaces of the tree + :type namespaces: str + + """ + itype = self._check_for_tag(root, namespaces, "itype") + if itype : + method_name = '_inform_'+ itype.replace('.', '_').lower() + method = getattr(self, method_name) + if method : + method(root, namespaces) + else : + msg = "There is no method to parse the response of the type " + itype + self.info(msg) + return + + +
[docs] def check_mailbox(self, itype, attr): + """ Check the mail box + + :param itype: type of mail + :type itype: str + :param attr: value wanted + :type attr: str + + """ + if itype == "create": + for res in self.mailbox[itype]: + binary, uid = res + if binary == attr: + self.mailbox[itype].remove(res) + return uid + else : + for res in self.mailbox[itype]: + if attr == res: + self.mailbox[itype].remove(res) + return res + +
+
[docs] def handle(self, iq): + """ Check the mail box + + :param iq: message received + :type itype: iq + """ + namespaces = "{http://schema.mytestbed.net/omf/6.0/protocol}" + for i in iq['pubsub_event']['items']: + root = ET.fromstring(str(i)) + #ET.dump(root) + self._parse_inform(root, namespaces) +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_api_factory.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_api_factory.html new file mode 100644 index 00000000..3e59d3b6 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_api_factory.html @@ -0,0 +1,230 @@ + + + + + + + + nepi.resources.omf.omf_api_factory — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.omf_api_factory

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+
+import time
+import hashlib
+import threading
+
+from nepi.resources.omf.omf5_api import OMF5API
+from nepi.resources.omf.omf6_api import OMF6API
+
+
[docs]class OMFAPIFactory(object): + """ + .. note:: + + It allows the different RM to use the same xmpp client if they use + the same credentials. For the moment, it is focused on XMPP. + + """ + # use lock to avoid concurrent access to the Api list at the same times by 2 + # different threads + lock = threading.Lock() + _apis = dict() + + @classmethod +
[docs] def get_api(cls, version, server, user, port, password, exp_id = None): + """ Get an OMF Api + + :param version: OMF Version. Either 5 or 6 + :type version: str + :param server: Xmpp Server Adress + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port (Default : 5222) + :type port: str + :param password: Xmpp Password + :type password: str + :param exp_id: Id of the experiment + :type exp_id: str + + """ + if version and user and server and port and password: + key = cls._make_key(version, server, user, port, password, exp_id) + cls.lock.acquire() + if key in cls._apis: + #print "Api Counter : " + str(cls._apis[key]['cnt']) + cls._apis[key]['cnt'] += 1 + cls.lock.release() + return cls._apis[key]['api'] + else : + omf_api = cls.create_api(version, server, user, port, password, exp_id) + cls.lock.release() + return omf_api + return None +
+ @classmethod +
[docs] def create_api(cls, version, server, user, port, password, exp_id): + """ Create an OMF API if this one doesn't exist yet with this credentials + + :param version: OMF Version. Either 5 or 6 + :type version: str + :param server: Xmpp Server Adress + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port (Default : 5222) + :type port: str + :param password: Xmpp Password + :type password: str + :param exp_id: Id of the experiment + :type exp_id: str + + """ + key = cls._make_key(version, server, user, port, password, exp_id) + if version == "5": + omf_api = OMF5API(server, user, port, password, exp_id = exp_id) + else : + omf_api = OMF6API(server, user = user, port = port, password = password, exp_id = exp_id) + cls._apis[key] = {} + cls._apis[key]['api'] = omf_api + cls._apis[key]['cnt'] = 1 + return omf_api +
+ @classmethod +
[docs] def release_api(cls, version, server, user, port, password, exp_id = None): + """ Release an OMF API with this credentials + + :param version: OMF Version. Either 5 or 6 + :type version: str + :param server: Xmpp Server Adress + :type server: str + :param user: Xmpp User + :type user: str + :param port: Xmpp Port (Default : 5222) + :type port: str + :param password: Xmpp Password + :type password: str + :param exp_id: Id of the experiment + :type exp_id: str + + """ + if version and user and server and port and password: + key = cls._make_key(version, server, user, port, password, exp_id) + if key in cls._apis: + cls._apis[key]['cnt'] -= 1 + #print "Api Counter : " + str(cls._apis[key]['cnt']) + if cls._apis[key]['cnt'] == 0: + omf_api = cls._apis[key]['api'] + omf_api.disconnect() + del cls._apis[key] +
+ @classmethod + def _make_key(cls, *args): + """ Hash the credentials in order to create a key + + :param args: list of arguments used to create the hash (server, user, port, ...) + :type args: list + + """ + skey = "".join(map(str, args)) + return hashlib.md5(skey).hexdigest() +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_client.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_client.html new file mode 100644 index 00000000..52922bc5 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_client.html @@ -0,0 +1,449 @@ + + + + + + + + nepi.resources.omf.omf_client — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.omf_client

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+from nepi.util.logger import Logger
+from nepi.resources.omf.omf6_parser import OMF6Parser
+try:
+    import sleekxmpp
+    from sleekxmpp.exceptions import IqError, IqTimeout
+    class BaseOMFClient(sleekxmpp.ClientXMPP):
+        pass
+except ImportError:
+    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)
+
+
[docs] class BaseOMFClient(object): + pass +
+import traceback +import xml.etree.ElementTree as ET + +# inherit from BaseXmpp and XMLstream classes +
[docs]class OMFClient(BaseOMFClient, Logger): + """ + .. class:: Class Args : + + :param jid: Jabber Id (= Xmpp Slice + Date) + :type jid: str + :param password: Jabber Password (= Xmpp Password) + :type password: str + + .. note:: + + This class is an XMPP Client with customized method + + """ + + def __init__(self, jid, password): + """ + + :param jid: Jabber Id (= Xmpp Slice + Date) + :type jid: str + :param password: Jabber Password (= Xmpp Password) + :type password: str + + + """ + Logger.__init__(self, "OMFClient") + + sleekxmpp.ClientXMPP.__init__(self, jid, password) + self._ready = False + self._registered = False + self._server = None + self._parser = None + + self.register_plugin('xep_0077') # In-band registration + self.register_plugin('xep_0030') + self.register_plugin('xep_0059') + self.register_plugin('xep_0060') # PubSub + + self.add_event_handler("session_start", self.start) + self.add_event_handler("register", self.register) + self.add_event_handler("pubsub_publish", self.handle_omf_message) + + #Init the parser + self._init_parser() + + def _init_parser(self): + """ Init the parser depending on the OMF Version + + """ + self._parser = OMF6Parser() + + @property +
[docs] def ready(self): + """ Check if the client is ready + + """ + return self._ready +
+
[docs] def start(self, event): + """ Send presence to the Xmppp Server. This function is called directly by the sleekXmpp library + + """ + self.send_presence() + self._ready = True + self._server = "pubsub.%s" % self.boundjid.domain +
+
[docs] def register(self, iq): + """ Register to the Xmppp Server. This function is called directly by the sleekXmpp library + + """ + if self._registered: + msg = " %s already registered!" % self.boundjid + self.info(msg) + return + + resp = self.Iq() + resp['type'] = 'set' + resp['register']['username'] = self.boundjid.user + resp['register']['password'] = self.password + + try: + resp.send(now=True) + msg = " Account created for %s!" % self.boundjid + self.info(msg) + self._registered = True + except IqError as e: + msg = " Could not register account: %s" % e.iq['error']['text'] + self.error(msg) + except IqTimeout: + msg = " No response from server." + self.error(msg) +
+
[docs] def unregister(self): + """ Unregister from the Xmppp Server. + + """ + try: + self.plugin['xep_0077'].cancel_registration( + ifrom=self.boundjid.full) + msg = " Account unregistered for %s!" % self.boundjid + self.info(msg) + except IqError as e: + msg = " Could not unregister account: %s" % e.iq['error']['text'] + self.error(msg) + except IqTimeout: + msg = " No response from server." + self.error(msg) +
+
[docs] def nodes(self): + """ Get all the nodes of the Xmppp Server. + + """ + try: + result = self['xep_0060'].get_nodes(self._server) + for item in result['disco_items']['items']: + msg = ' - %s' % str(item) + self.debug(msg) + return result + except: + error = traceback.format_exc() + msg = 'Could not retrieve node list.\ntraceback:\n%s' % error + self.error(msg) +
+
[docs] def subscriptions(self): + """ Get all the subscriptions of the Xmppp Server. + + """ + try: + result = self['xep_0060'].get_subscriptions(self._server) + #self.boundjid.full) + for node in result['node']: + msg = ' - %s' % str(node) + self.debug(msg) + return result + except: + error = traceback.format_exc() + msg = ' Could not retrieve subscriptions.\ntraceback:\n%s' % error + self.error(msg) +
+
[docs] def create(self, node): + """ Create the topic corresponding to the node + + :param node: Name of the topic, corresponding to the node (ex : omf.plexus.wlab17) + :type node: str + + """ + msg = " Create Topic : " + node + self.info(msg) + + config = self['xep_0004'].makeForm('submit') + config.add_field(var='pubsub#node_type', value='leaf') + config.add_field(var='pubsub#notify_retract', value='0') + config.add_field(var='pubsub#publish_model', value='open') + config.add_field(var='pubsub#persist_items', value='1') + config.add_field(var='pubsub#max_items', value='1') + config.add_field(var='pubsub#title', value=node) + + try: + self['xep_0060'].create_node(self._server, node, config = config) + except: + #error = traceback.format_exc() + #msg = ' Could not create topic: %s\ntraceback:\n%s' % (node, error) + msg = 'Could not create the topic : '+node+' . Maybe the topic already exists' + self.error(msg) +
+
[docs] def delete(self, node): + """ Delete the topic corresponding to the node + + :param node: Name of the topic, corresponding to the node (ex : omf.plexus.wlab17) + :type node: str + + """ + # To check if the queue are well empty at the end + #print " length of the queue : " + str(self.send_queue.qsize()) + #print " length of the queue : " + str(self.event_queue.qsize()) + try: + self['xep_0060'].delete_node(self._server, node) + msg = ' Deleted node: %s' % node + self.info(msg) + except: + #error = traceback.format_exc() + #msg = ' Could not delete topic: %s\ntraceback:\n%s' % (node, error) + msg = 'Could not delete the topic : '+node+' . Maybe It is not the owner of the topic' + self.error(msg) +
+
[docs] def publish(self, data, node): + """ Publish the data to the corresponding topic + + :param data: Data that will be published + :type data: str + :param node: Name of the topic + :type node: str + + """ + + msg = " Publish to Topic : " + node + self.info(msg) + try: + result = self['xep_0060'].publish(self._server,node,payload=data) + # id = result['pubsub']['publish']['item']['id'] + # print('Published at item id: %s' % id) + except: + error = traceback.format_exc() + msg = ' Could not publish to: %s\ntraceback:\n%s' % (node, error) + self.error(msg) +
+
[docs] def get(self, data): + """ Get the item + + :param data: data from which the items will be get back + :type data: str + + + """ + try: + result = self['xep_0060'].get_item(self._server, self.boundjid, + data) + for item in result['pubsub']['items']['substanzas']: + msg = 'Retrieved item %s: %s' % (item['id'], tostring(item['payload'])) + self.debug(msg) + except: + error = traceback.format_exc() + msg = ' Could not retrieve item %s from topic %s\ntraceback:\n%s' \ + % (data, self.boundjid, error) + self.error(msg) +
+
[docs] def retract(self, data): + """ Retract the item + + :param data: data from which the item will be retracted + :type data: str + + """ + try: + result = self['xep_0060'].retract(self._server, self.boundjid, data) + msg = ' Retracted item %s from topic %s' % (data, self.boundjid) + self.debug(msg) + except: + error = traceback.format_exc() + msg = 'Could not retract item %s from topic %s\ntraceback:\n%s' \ + % (data, self.boundjid, error) + self.error(msg) +
+
[docs] def purge(self): + """ Purge the information in the server + + """ + try: + result = self['xep_0060'].purge(self._server, self.boundjid) + msg = ' Purged all items from topic %s' % self.boundjid + self.debug(msg) + except: + error = traceback.format_exc() + msg = ' Could not purge items from topic %s\ntraceback:\n%s' \ + % (self.boundjid, error) + self.error(msg) +
+
[docs] def subscribe(self, node): + """ Subscribe to a topic + + :param node: Name of the topic + :type node: str + + """ + try: + result = self['xep_0060'].subscribe(self._server, node) + msg = ' Subscribed %s to topic %s' \ + % (self.boundjid.user, node) + #self.info(msg) + self.debug(msg) + except: + error = traceback.format_exc() + msg = ' Could not subscribe %s to topic %s\ntraceback:\n%s' \ + % (self.boundjid.bare, node, error) + self.error(msg) +
+
[docs] def unsubscribe(self, node): + """ Unsubscribe to a topic + + :param node: Name of the topic + :type node: str + + """ + try: + result = self['xep_0060'].unsubscribe(self._server, node) + msg = ' Unsubscribed %s from topic %s' % (self.boundjid.bare, node) + self.debug(msg) + except: + error = traceback.format_exc() + msg = ' Could not unsubscribe %s from topic %s\ntraceback:\n%s' \ + % (self.boundjid.bare, node, error) + self.error(msg) +
+
[docs] def check_mailbox(self, itype, attr): + """ Check the mail box + + :param itype: type of mail + :type itype: str + :param attr: value wanted + :type attr: str + + """ + return self._parser.check_mailbox(itype, attr) + +
+
[docs] def handle_omf_message(self, iq): + """ Handle published/received message + + :param iq: Stanzas that is currently published/received + :type iq: Iq Stanza + + """ + self._parser.handle(iq) +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_resource.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_resource.html new file mode 100644 index 00000000..d88f1218 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/omf_resource.html @@ -0,0 +1,167 @@ + + + + + + + + nepi.resources.omf.omf_resource — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.omf_resource

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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: Julien Tribino <julien.tribino@inria.fr>
+#         Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState
+
+
+
[docs]class ResourceGateway: + """ + Dictionary used to set OMF gateway depending on Testbed information. + """ + #XXX: A.Q. COMMENT: This looks a bit hardcoded + # SHOULDN'T THIS BE IN A SEPARATED FILE RATHER THAN IN THE + # BASE CLASS FOR ALL OMF RESOURCES? + TestbedtoGateway = dict({ + "wilabt" : "ops.wilab2.ilabt.iminds.be", + "nitos" : "nitlab.inf.uth.gr", + "nicta" : "??.??.??", + }) + + AMtoGateway = dict({ + "am.wilab2.ilabt.iminds.be" : "ops.wilab2.ilabt.iminds.be", + "nitlab.inf.uth.gr" : "nitlab.inf.uth.gr", + "nicta" : "??.??.??", + }) +
+@clsinit_copy +
[docs]class OMFResource(ResourceManager): + """ + Generic resource gathering XMPP credential information and common methods + for OMF nodes, channels, applications, etc. + """ + _rtype = "abstract::omf::Resource" + _platform = "omf" + + @classmethod + def _register_attributes(cls): + + xmppServer = Attribute("xmppServer", "Xmpp Server", + flags = Flags.Credential) + xmppUser = Attribute("xmppUser","Name of the Xmpp User/Slice", + flags = Flags.Credential) + xmppPort = Attribute("xmppPort", "Xmpp Port", + flags = Flags.Credential) + xmppPassword = Attribute("xmppPassword", "Xmpp Password", + flags = Flags.Credential) + version = Attribute("version", "Version of OMF : Either 5 or 6", + default = "6", ) + + cls._register_attribute(xmppUser) + cls._register_attribute(xmppServer) + cls._register_attribute(xmppPort) + cls._register_attribute(xmppPassword) + cls._register_attribute(version) + + def __init__(self, ec, guid): + super(OMFResource, self).__init__(ec, guid) + pass +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/omf/wilabt_node.html b/doc/sphinx/_build/html/_modules/nepi/resources/omf/wilabt_node.html new file mode 100644 index 00000000..ff95e487 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/omf/wilabt_node.html @@ -0,0 +1,559 @@ + + + + + + + + nepi.resources.omf.wilabt_node — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.omf.wilabt_node

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 
+from nepi.resources.omf.node import OMFNode
+from nepi.util.sfaapi import SFAAPIFactory 
+from nepi.util.execfuncs import lexec
+from nepi.util import sshfuncs
+
+from random import randint
+import time
+import re
+import weakref
+import socket
+import threading
+import datetime
+
+@clsinit_copy
+
[docs]class WilabtSfaNode(OMFNode): + _rtype = "wilabt::sfa::Node" + _help = "Controls a Wilabt host accessible using a SSH key " \ + "and provisioned using SFA" + _platform = "omf" + + @classmethod + def _register_attributes(cls): + + username = Attribute("username", "Local account username", + flags = Flags.Credential) + + identity = Attribute("identity", "SSH identity file", + flags = Flags.Credential) + + server_key = Attribute("serverKey", "Server public key", + flags = Flags.Design) + + 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", + flags = Flags.Credential) + + slicename = Attribute("slicename", "SFA slice for the experiment", + flags = Flags.Credential) + + gateway_user = Attribute("gatewayUser", "Gateway account username", + flags = Flags.Design) + + gateway = Attribute("gateway", "Hostname of the gateway machine", + flags = Flags.Design) + + host = Attribute("host", "Name of the physical machine", + flags = Flags.Design) + + disk_image = Attribute("disk_image", "Specify a specific disk image for a node", + flags = Flags.Design) + + cls._register_attribute(username) + cls._register_attribute(identity) + cls._register_attribute(server_key) + cls._register_attribute(sfa_user) + cls._register_attribute(sfa_private_key) + cls._register_attribute(slicename) + cls._register_attribute(gateway_user) + cls._register_attribute(gateway) + cls._register_attribute(host) + cls._register_attribute(disk_image) + + def __init__(self, ec, guid): + super(WilabtSfaNode, self).__init__(ec, guid) + + self._ecobj = weakref.ref(ec) + self._sfaapi = None + self._node_to_provision = None + self._slicenode = False + self._host = False + self._username = None + + def _skip_provision(self): + sfa_user = self.get("sfauser") + if not sfa_user: + return True + else: return False + + @property +
[docs] def sfaapi(self): + """ + Property to instanciate the SFA API based in sfi client. + For each SFA method called this instance is used. + """ + if not self._sfaapi: + sfa_user = self.get("sfauser") + sfa_sm = "http://www.wilab2.ilabt.iminds.be:12369/protogeni/xmlrpc/am/3.0" + sfa_auth = '.'.join(sfa_user.split('.')[:2]) + sfa_registry = "http://sfa3.planet-lab.eu:12345/" + sfa_private_key = self.get("sfaPrivateKey") + batch = True + + _sfaapi = SFAAPIFactory.get_api(sfa_user, sfa_auth, + sfa_registry, sfa_sm, sfa_private_key, self._ecobj(), batch, WilabtSfaNode._rtype) + + if not _sfaapi: + self.fail_sfaapi() + + self._sfaapi = weakref.ref(_sfaapi) + + return self._sfaapi() +
+
[docs] def do_discover(self): + """ + Based on the attributes defined by the user, discover the suitable + node for provision. + """ + nodes = self.sfaapi.get_resources_hrn() + + host = self._get_host() + if host: + # the user specified one particular node to be provisioned + self._host = True + host_hrn = nodes[host] + + # 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): + if self._check_if_in_slice([host_hrn]): + self.debug("Node already in slice %s" % host_hrn) + self._slicenode = True + host = host + '.wilab2.ilabt.iminds.be' + self.set('host', host) + self._node_to_provision = host_hrn + super(WilabtSfaNode, self).do_discover() +
+
[docs] def do_provision(self): + """ + Add node to user's slice and verifing that the node is functioning + correctly. Check ssh, omf rc running, hostname, file system. + """ + provision_ok = False + ssh_ok = False + proc_ok = False + timeout = 300 + + while not provision_ok: + node = self._node_to_provision + #if self._slicenode: + # self._delete_from_slice() + # self.debug("Waiting 480 sec for re-adding to slice") + # time.sleep(480) # Timout for the testbed to allow a new reservation + self._add_node_to_slice(node) + t = 0 + while not self._check_if_in_slice([node]) and t < timeout \ + and not self._ecobj().abort: + t = t + 5 + time.sleep(t) + self.debug("Waiting 5 sec for resources to be added") + continue + + if not self._check_if_in_slice([node]): + self.debug("Couldn't add node %s to slice" % node) + self.fail_node_not_available(node) + + self._get_username() + ssh_ok = self._check_ssh_loop() + + if not ssh_ok: + # the timeout was reach without establishing ssh connection + # the node is blacklisted, and a new + # node to provision is discovered + self._blacklist_node(node) + self.do_discover() + continue + + # check /proc directory is mounted (ssh_ok = True) + # file system is not read only, hostname is correct + # and omf_rc process is up + else: + if not self._check_fs(): + self.do_discover() + continue + if not self._check_omfrc(): + self.do_discover() + continue + if not self._check_hostname(): + self.do_discover() + continue + + else: + provision_ok = True + if not self.get('host'): + self._set_host_attr(node) + self.info(" Node provisioned ") + + super(WilabtSfaNode, self).do_provision() +
+
[docs] def do_deploy(self): + if self.state == ResourceState.NEW: + self.info("Deploying w-iLab.t node") + self.do_discover() + self.do_provision() + super(WilabtSfaNode, self).do_deploy() +
+
[docs] def do_release(self): + super(WilabtSfaNode, self).do_release() + if self.state == ResourceState.RELEASED and not self._skip_provision(): + self.debug(" Releasing SFA API ") + self.sfaapi.release() +
+ def _blacklisted(self, host_hrn): + """ + Check in the SFA API that the node is not in the blacklist. + """ + if self.sfaapi.blacklisted(host_hrn): + self.fail_node_not_available(host_hrn) + return False + + def _reserved(self, host_hrn): + """ + Check in the SFA API that the node is not in the reserved + list. + """ + if self.sfaapi.reserved(host_hrn): + self.fail_node_not_available(host_hrn) + return False + + def _get_username(self): + """ + Get the username for login in to the nodes from RSpec. + Wilabt username is not made out of any convention, it + has to be retrived from the manifest RSpec. + """ + slicename = self.get("slicename") + if self._username is None: + slice_info = self.sfaapi.get_slice_resources(slicename) + username = slice_info['resource'][0]['services'][0]['login'][0]['username'] + self.set('username', username) + self.debug("Retriving username information from RSpec %s" % username) + self._username = username + + def _check_ssh_loop(self): + """ + Check that the ssh login is possible. In wilabt is done + through the gateway because is private testbed. + """ + t = 0 + timeout = 1200 + ssh_ok = False + 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 20s" ) + t = t + 20 + time.sleep(20) + continue + else: + self.debug( "SSH OK" ) + ssh_ok = True + continue + return ssh_ok + + def _check_fs(self): + """ + Check file system, /proc well mounted. + """ + cmd = 'mount |grep proc' + ((out, err), proc) = self.execute(cmd) + if out.find("/proc type proc") < 0: + self.warning(" Corrupted file system ") + self._blacklist_node(node) + return False + return True + + def _check_omfrc(self): + """ + Check that OMF 6 resource controller is running. + """ + cmd = 'ps aux|grep omf' + ((out, err), proc) = self.execute(cmd) + if out.find("/usr/local/rvm/gems/ruby-1.9.3-p286@omf/bin/omf_rc") < 0: + return False + return True + + def _check_hostname(self): + """ + Check that the hostname in the image is not set to localhost. + """ + cmd = 'hostname' + ((out, err), proc) = self.execute(cmd) + if 'localhost' in out.lower(): + return False + else: + self.set('hostname', out.strip()) + return True + +
[docs] def execute(self, command, + sudo = False, + env = None, + tty = False, + forward_x11 = False, + retry = 3, + connect_timeout = 30, + strict_host_checking = False, + persistent = True, + blocking = True, + ): + """ Notice that this invocation will block until the + execution finishes. If this is not the desired behavior, + use 'run' instead.""" + (out, err), proc = sshfuncs.rexec( + command, + host = self.get("host"), + user = self.get("username"), + port = 22, + gwuser = self.get("gatewayUser"), + gw = self.get("gateway"), + agent = True, + sudo = sudo, + identity = self.get("identity"), + server_key = self.get("serverKey"), + env = env, + tty = tty, + forward_x11 = forward_x11, + retry = retry, + connect_timeout = connect_timeout, + persistent = persistent, + blocking = blocking, + strict_host_checking = strict_host_checking + ) + + return (out, err), proc + +
+ def _add_node_to_slice(self, host_hrn): + """ + Add node to slice, using SFA API. Actually Wilabt testbed + doesn't allow adding nodes, in fact in the API there is method + to group all the nodes instanciated as WilabtSfaNodes and the + Allocate and Provision is done with the last call at + sfaapi.add_resource_to_slice_batch. + """ + self.info(" Adding node to slice ") + slicename = self.get("slicename") + disk_image = self.get("disk_image") + if disk_image is not None: + properties = {'disk_image': disk_image} + else: properties = None + #properties = None + self.sfaapi.add_resource_to_slice_batch(slicename, host_hrn, properties=properties) + + def _delete_from_slice(self): + """ + Delete every node from slice, using SFA API. + Wilabt doesn't allow to remove one sliver so this method + remove every slice from the slice. + """ + + self.warning(" Deleting all slivers from slice ") + slicename = self.get("slicename") + self.sfaapi.remove_all_from_slice(slicename) + + def _get_host(self): + """ + Get the attribute hostname. + """ + host = self.get("host") + if host: + return host + else: + return None + + def _set_host_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 host, hrn in hosts_hrn.iteritems(): + if hrn == node: + host = host + '.wilab2.ilabt.iminds.be' + self.set("host", host) + + 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("slicename") + slice_nodes = self.sfaapi.get_slice_resources(slicename)['resource'] + if slice_nodes: + if len(slice_nodes[0]['services']) != 0: + slice_nodes_hrn = self.sfaapi.get_resources_hrn(slice_nodes).values() + else: slice_nodes_hrn = [] + nodes_inslice = list(set(hosts_hrn) & set(slice_nodes_hrn)) + return nodes_inslice + + def _blacklist_node(self, host_hrn): + """ + Add mal functioning node to blacklist (in SFA API). + """ + self.warning(" Blacklisting malfunctioning node ") + self.sfaapi.blacklist_resource(host_hrn) + if not self._host: + self.set('host', None) + else: + self.set('host', host_hrn.split('.').pop()) + + def _put_node_in_provision(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, host): + """ + Query cache for the IP of a node with certain hostname + """ + try: + ip = sshfuncs.gethostbyname(host) + except: + # Fail while trying to find the IP + return None + return ip + +
[docs] def fail_discovery(self): + msg = "Discovery failed. No candidates found for node" + self.error(msg) + raise RuntimeError, msg +
+
[docs] def fail_node_not_alive(self, host=None): + msg = "Node %s not alive" % host + raise RuntimeError, msg +
+
[docs] def fail_node_not_available(self, host): + msg = "Some nodes not available for provisioning" + raise RuntimeError, msg +
+
[docs] def fail_not_enough_nodes(self): + msg = "Not enough nodes available for provisioning" + raise RuntimeError, msg +
+
[docs] def fail_sfaapi(self): + msg = "Failing while trying to instanciate the SFA API." + raise RuntimeError, msg +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/node.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/node.html new file mode 100644 index 00000000..7b867949 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/node.html @@ -0,0 +1,775 @@ + + + + + + + + nepi.resources.planetlab.node — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.node

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 <lucia.guevgeozian_odizzio@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState 
+from nepi.resources.linux.node import LinuxNode
+from nepi.resources.planetlab.plcapi import PLCAPIFactory 
+from nepi.util.execfuncs import lexec
+from nepi.util import sshfuncs
+
+from random import randint
+import re
+import os
+import time
+import socket
+import threading
+import datetime
+import weakref
+
+@clsinit_copy
+
[docs]class PlanetlabNode(LinuxNode): + _rtype = "planetlab::Node" + _help = "Controls a PlanetLab host accessible using a SSH key " \ + "associated to a PlanetLab user account" + _platform = "planetlab" + + lock = threading.Lock() + + @classmethod + def _register_attributes(cls): + ip = Attribute("ip", "PlanetLab host public IP address", + flags = Flags.Design) + + pl_url = Attribute("plcApiUrl", "URL of PlanetLab PLCAPI host \ + (e.g. www.planet-lab.eu or www.planet-lab.org) ", + default = "www.planet-lab.eu", + flags = Flags.Credential) + + pl_ptn = Attribute("plcApiPattern", "PLC API service regexp pattern \ + (e.g. https://%(hostname)s:443/PLCAPI/ ) ", + default = "https://%(hostname)s:443/PLCAPI/", + flags = Flags.Design) + + pl_user = Attribute("pluser", "PlanetLab account user, as the one to \ + authenticate in the website) ", + flags = Flags.Credential) + + pl_password = Attribute("plpassword", + "PlanetLab account password, as \ + the one to authenticate in the website) ", + flags = Flags.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(ip) + cls._register_attribute(pl_url) + cls._register_attribute(pl_ptn) + cls._register_attribute(pl_user) + cls._register_attribute(pl_password) + 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(PlanetlabNode, self).__init__(ec, guid) + + self._ecobj = weakref.ref(ec) + self._plapi = 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) + + # Blacklist file + 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() + + def _skip_provision(self): + pl_user = self.get("pluser") + pl_pass = self.get("plpassword") + if not pl_user and not pl_pass: + return True + else: return False + + @property +
[docs] def plapi(self): + if not self._plapi: + pl_user = self.get("pluser") + pl_pass = self.get("plpassword") + pl_url = self.get("plcApiUrl") + pl_ptn = self.get("plcApiPattern") + _plapi = PLCAPIFactory.get_api(pl_user, pl_pass, pl_url, + pl_ptn, self._ecobj()) + + if not _plapi: + self.fail_plapi() + + self._plapi = weakref.ref(_plapi) + + return self._plapi() +
+
[docs] def do_discover(self): + """ + Based on the attributes defined by the user, discover the suitable + nodes for provision. + """ + if self._skip_provision(): + super(PlanetlabNode, self).do_discover() + return + + hostname = self._get_hostname() + if hostname: + # the user specified one particular node to be provisioned + self._hostname = True + node_id = self._get_nodes_id({'hostname':hostname}) + node_id = node_id.pop()['node_id'] + + # check that the node is not blacklisted or being provisioned + # by other RM + with PlanetlabNode.lock: + plist = self.plapi.reserved() + blist = self.plapi.blacklisted() + if node_id not in blist and node_id not in plist: + + # check that is really alive, by performing ping + ping_ok = self._do_ping(node_id) + if not ping_ok: + self._blacklist_node(node_id) + self.fail_node_not_alive(hostname) + else: + if self._check_if_in_slice([node_id]): + self._slicenode = True + self._put_node_in_provision(node_id) + self._node_to_provision = node_id + else: + self.fail_node_not_available(hostname) + super(PlanetlabNode, 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(PlanetlabNode, self).do_discover() + except: + with PlanetlabNode.lock: + self._blacklist_node(node_id) + self.do_discover() + else: + self.fail_not_enough_nodes() +
+
[docs] def do_provision(self): + """ + Add node to user's slice after verifing that the node is functioning + correctly + """ + if self._skip_provision(): + super(PlanetlabNode, 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) + 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: + + 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 + with PlanetlabNode.lock: + self.warning(" Could not SSH login ") + self._blacklist_node(node) + #self._delete_node_from_slice(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(): + with PlanetlabNode.lock: + self.warning(" Corrupted file system ") + self._blacklist_node(node) + #self._delete_node_from_slice(node) + self.do_discover() + continue + + else: + provision_ok = True + if not self.get('hostname'): + self._set_hostname_attr(node) + # set IP attribute + ip = self._get_ip(node) + self.set("ip", ip) + self.info(" Node provisioned ") + + super(PlanetlabNode, self).do_provision() +
+
[docs] def do_release(self): + super(PlanetlabNode, self).do_release() + if self.state == ResourceState.RELEASED and not self._skip_provision(): + 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 + """ + # 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_id = [] + 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_id = self._filter_by_fixed_attr(filters, nodes_id) + + # filter nodes by range constraints e.g. max bandwidth + elif ('min' or 'max') in attr_name: + nodes_id = self._filter_by_range_attr(attr_name, attr_value, filters, nodes_id) + + if not filters: + nodes = self._get_nodes_id() + for node in nodes: + nodes_id.append(node['node_id']) + return nodes_id + + def _filter_by_fixed_attr(self, filters, nodes_id): + """ + Query PLCAPI for nodes ids matching fixed attributes defined by the + user + """ + node_tags = self.plapi.get_node_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 + """ + 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.warning(" 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, node_id): + self.info(" Adding node to slice ") + 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.warning(" 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 + ip = self.get("ip") + if ip: + hostname = socket.gethostbyaddr(ip)[0] + self.set('hostname', hostname) + return hostname + else: + return None + + def _set_hostname_attr(self, node): + """ + Query PLCAPI for the hostname of a certain node id and sets the + attribute hostname, it will over write the previous value + """ + hostname = self.plapi.get_nodes(node, ['hostname']) + self.set("hostname", hostname[0]['hostname']) + + def _check_if_in_slice(self, nodes_id): + """ + Query PLCAPI to find out if any node id from nodes_id is in the user's + slice + """ + slicename = self.get("username") + slice_nodes = self.plapi.get_slice_nodes(slicename) + nodes_inslice = list(set(nodes_id) & set(slice_nodes)) + return nodes_inslice + + def _do_ping(self, node_id): + """ + Perform ping command on node's IP matching node id + """ + ping_ok = False + ip = self._get_ip(node_id) + 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.warning(" Blacklisting malfunctioning node ") + self.plapi.blacklist_host(node) + if not self._hostname: + self.set('hostname', None) + + def _put_node_in_provision(self, node): + """ + Add node to the list of nodes being provisioned, in order for other RMs + to not try to provision the same one again + """ + self.plapi.reserve_host(node) + + def _get_ip(self, node_id): + """ + Query PLCAPI for the IP of a node with certain node id + """ + hostname = self.get("hostname") or \ + self.plapi.get_nodes(node_id, ['hostname'])[0]['hostname'] + try: + ip = sshfuncs.gethostbyname(hostname) + except: + # Fail while trying to find the IP + return None + return ip + +
[docs] def fail_discovery(self): + msg = "Discovery failed. No candidates found for node" + self.error(msg) + raise RuntimeError, msg +
+
[docs] def fail_node_not_alive(self, hostname=None): + msg = "Node %s not alive" % hostname + raise RuntimeError, msg +
+
[docs] def fail_node_not_available(self, hostname): + msg = "Node %s not available for provisioning" % hostname + raise RuntimeError, msg +
+
[docs] def fail_not_enough_nodes(self): + msg = "Not enough nodes available for provisioning" + raise RuntimeError, msg +
+
[docs] def fail_plapi(self): + msg = "Failing while trying to instanciate the PLC API.\nSet the" + \ + " attributes pluser and plpassword." + raise RuntimeError, msg +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/fdudptunnel.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/fdudptunnel.html new file mode 100644 index 00000000..a0543e36 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/fdudptunnel.html @@ -0,0 +1,164 @@ + + + + + + + + nepi.resources.planetlab.ns3.fdudptunnel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.ns3.fdudptunnel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+from nepi.resources.linux.ns3.fdudptunnel import LinuxNs3FdUdpTunnel
+from nepi.util.sshfuncs import ProcStatus
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import base64
+import os
+import socket
+import time
+
+@clsinit_copy
+
[docs]class PlanetlabNs3FdUdpTunnel(LinuxNs3FdUdpTunnel): + _rtype = "planetlab::ns3::FdUdpTunnel" + _help = "Constructs a tunnel between two Ns-3 FdNetdevices " \ + "located in remote PlanetLab nodes using a UDP connection " + _platform = "planetlab::ns3" + +
[docs] def get_endpoints(self): + """ Returns the list of RM that are endpoints to the tunnel + """ + if not self._fd2 or not self._fd1: + from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice + devices = self.get_connected(NS3BaseFdNetDevice.get_rtype()) + if not devices or len(devices) != 2: + msg = "Tunnel must be connected to exactly two FdNetDevices" + self.error(msg) + raise RuntimeError, msg + + self._fd1 = devices[0] + self._fd2 = devices[1] + self._pi = True + + # Set PI headers on + self._fd1.set("EncapsulationMode", "DixPi") + self._fd2.set("EncapsulationMode", "DixPi") + + simu = self._fd1.simulation + from nepi.resources.linux.node import LinuxNode + nodes = simu.get_connected(LinuxNode.get_rtype()) + self._fd1node = nodes[0] + + simu = self._fd2.simulation + from nepi.resources.linux.node import LinuxNode + nodes = simu.get_connected(LinuxNode.get_rtype()) + self._fd2node = nodes[0] + + if self._fd1node.get("hostname") == \ + self._fd2node.get("hostname"): + msg = "Tunnel requires endpoints on different hosts" + self.error(msg) + raise RuntimeError, msg + + return [self._fd1, self._fd2] +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/tuntapfdlink.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/tuntapfdlink.html new file mode 100644 index 00000000..ffbc91c3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/ns3/tuntapfdlink.html @@ -0,0 +1,183 @@ + + + + + + + + nepi.resources.planetlab.ns3.tuntapfdlink — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.ns3.tuntapfdlink

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 ResourceState, clsinit_copy
+from nepi.resources.linux.ns3.tuntapfdlink import LinuxTunTapFdLink
+
+import base64
+import fcntl
+import os
+import socket
+import struct
+
+@clsinit_copy
+
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovs.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovs.html new file mode 100644 index 00000000..a1198604 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovs.html @@ -0,0 +1,406 @@ + + + + + + + + nepi.resources.planetlab.openvswitch.ovs — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.openvswitch.ovs

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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/>.
+#
+# Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
+#         Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.execution.attribute import Attribute, Flags
+from nepi.resources.planetlab.node import PlanetlabNode        
+from nepi.resources.linux.application import LinuxApplication
+import os
+
+@clsinit_copy                    
+
[docs]class PlanetlabOVSSwitch(LinuxApplication): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + + _rtype = "planetlab::OVSSwitch" + _help = "Runs an OpenVSwitch on a PlanetLab host" + _platform = "planetlab" + + _authorized_connections = ["planetlab::Node", "planetla::OVSPort", "linux::Node"] + + @classmethod + def _register_attributes(cls): + """ Register the attributes of OVSSwitch RM + + """ + bridge_name = Attribute("bridge_name", + "Name of the switch/bridge", + flags = Flags.Design) + virtual_ip_pref = Attribute("virtual_ip_pref", + "Virtual IP/PREFIX of the switch", + flags = Flags.Design) + controller_ip = Attribute("controller_ip", + "IP of the controller", + flags = Flags.Design) + controller_port = Attribute("controller_port", + "Port of the controller", + flags = Flags.Design) + + cls._register_attribute(bridge_name) + cls._register_attribute(virtual_ip_pref) + cls._register_attribute(controller_ip) + cls._register_attribute(controller_port) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + super(PlanetlabOVSSwitch, self).__init__(ec, guid) + self._home = "ovsswitch-%s" % self.guid + self._node = None + + @property +
[docs] def node(self): + """ Node wthat run the switch + """ + if not self._node: + nodes = self.get_connected(PlanetlabNode.get_rtype()) + if not nodes or len(nodes) != 1: + msg = "PlanetlabOVSSwitch must be connected to exactly one PlanetlabNode" + #self.error(msg) + raise RuntimeError, msg + + self._node = nodes[0] + + return self._node +
+
[docs] def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() not in self._authorized_connections: + return False + return True +
+
[docs] def do_provision(self): + self.node.mkdir(self.run_home) + + self.check_sliver_ovs() + self.servers_on() + self.create_bridge() + self.assign_controller() + self.ovs_status() + + self.set_provisioned() +
+
[docs] def do_deploy(self): + """ Deploy the OVS Switch : Turn on the server, create the bridges + and assign the controller + """ + + if not self.node or self.node.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def check_sliver_ovs(self): + """ Check if sliver-ovs exists. If it does not exist, the execution is stopped + """ + command = "compgen -c | grep sliver-ovs" + shfile = os.path.join(self.app_home, "check_ovs_cmd.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo = True, + pidfile="check_ovs_cmd_pidfile", + ecodefile="check_ovs_cmd_exitcode", + stdout="check_ovs_cmd_stdout", + stderr="check_ovs_cmd_stderr") + except RuntimeError: + msg = "Command sliver-ovs does not exist on the VM" + self.debug(msg) + raise RuntimeError, msg +
+
[docs] def servers_on(self): + """ Start the openvswitch servers and check it + """ + # Make sure the server is not running + command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name') + shfile = os.path.join(self.app_home, "clean.sh") + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + raise_on_error=False, + pidfile="clean_pidfile", + ecodefile="clean_exitcode", + stdout="clean_stdout", + stderr="clean_stderr") + + # start the server + command = "sliver-ovs start" + shfile = os.path.join(self.app_home, "start.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="start_pidfile", + ecodefile="start_exitcode", + stdout="start_stdout", + stderr="start_stderr") + except RuntimeError: + msg = "Failed to start ovs-server on VM" + self.debug(msg) + raise RuntimeError, msg + + command = "ps -A | grep ovsdb-server" + shfile = os.path.join(self.app_home, "ovsdb_status.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="ovsdb_status_pidfile", + ecodefile="ovsdb_status_exitcode", + stdout="ovsdb_status_stdout", + stderr="ovsdb_status_stderr") + except RuntimeError: + msg = "ovsdb-server not running on VM" + self.debug(msg) + raise RuntimeError, msg + + self.info("Server OVS Started...") +
+
[docs] def create_bridge(self): + """ Create the bridge/switch and check error during SSH connection + """ + # TODO: Check if previous bridge exist and delete them. Use ovs-vsctl list-br + # TODO: Add check for virtual_ip belonging to vsys_tag + if not (self.get("bridge_name") and self.get("virtual_ip_pref")): + msg = "No assignment in one or both attributes" + self.error(msg) + raise AttributeError, msg + + command = "sliver-ovs create-bridge '%s' '%s'" % ( + self.get("bridge_name"), + self.get("virtual_ip_pref")) + + shfile = os.path.join(self.app_home, "bridge_create.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="bridge_create_pidfile", + ecodefile="bridge_create_exitcode", + stdout="bridge_create_stdout", + stderr="bridge_create_stderr") + except RuntimeError: + msg = "No such pltap netdev\novs-appctl: ovs-vswitchd: server returned an error" + self.debug(msg) + raise RuntimeError, msg + + self.info(" Bridge %s Created and Assigned to %s" %\ + (self.get("bridge_name"), self.get("virtual_ip_pref")) ) +
+
[docs] def assign_controller(self): + """ Set the controller IP + """ + + if not (self.get("controller_ip") and self.get("controller_port")): + return + + """ + if not (self.get("controller_ip") and self.get("controller_port")): + msg = "No assignment in one or both attributes" + self.error(msg) + raise AttributeError, msg + """ + command = "ovs-vsctl set-controller %s tcp:%s:%s" % \ + (self.get("bridge_name"), + self.get("controller_ip"), + self.get("controller_port")) + + shfile = os.path.join(self.app_home, "set_controller.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="set_controller_pidfile", + ecodefile="set_controller_exitcode", + stdout="set_controller_stdout", + stderr="set_controller_stderr") + except RuntimeError: + msg = "SSH connection in the method assign_controller" + self.debug(msg) + raise RuntimeError, msg + + self.info("Controller assigned to the bridge %s" % self.get("bridge_name")) +
+
[docs] def ovs_status(self): + """ Print the status of the bridge + """ + command = "sliver-ovs show | tail -n +2" + shfile = os.path.join(self.app_home, "ovs_status.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="ovs_status_pidfile", + ecodefile="ovs_status_exitcode", + stdout="ovs_status_stdout", + stderr="ovs_status_stderr") + except RuntimeError: + msg = "Error when checking the status of the OpenVswitch" + self.debug(msg) + raise RuntimeError, msg +
+
[docs] def do_release(self): + """ Delete the bridge and close the server. + + .. note : It need to wait for the others RM (OVSPort and OVSTunnel) + to be released before releasing itself + + """ + + from nepi.resources.planetlab.openvswitch.ovsport import PlanetlabOVSPort + rms = self.get_connected(PlanetlabOVSPort.get_rtype()) + + for rm in rms: + if rm.state < ResourceState.RELEASED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + msg = "Deleting the bridge %s" % self.get('bridge_name') + self.info(msg) + + command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name') + shfile = os.path.join(self.app_home, "stop.sh") + + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="stop_pidfile", + ecodefile="stop_exitcode", + stdout="stop_stdout", + stderr="stop_stderr") + + super(PlanetlabOVSSwitch, self).do_release() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovsport.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovsport.html new file mode 100644 index 00000000..3ef19467 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/openvswitch/ovsport.html @@ -0,0 +1,384 @@ + + + + + + + + nepi.resources.planetlab.openvswitch.ovsport — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.openvswitch.ovsport

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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/>.
+#
+# Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
+#         Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import ResourceManager, clsinit_copy, \
+        ResourceState
+from nepi.resources.planetlab.openvswitch.ovs import PlanetlabOVSSwitch        
+from nepi.resources.planetlab.node import PlanetlabNode        
+from nepi.resources.linux.application import LinuxApplication
+
+import os
+
+@clsinit_copy                 
+
[docs]class PlanetlabOVSPort(LinuxApplication): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + + _rtype = "planetlab::OVSPort" + _help = "Runs an OpenVSwitch on a PlanetLab host" + _platform = "planetlab" + + _authorized_connections = ["planetlab::OVSSwitch", "linux::UdpTunnel", "linux::Tunnel"] + + @classmethod + def _register_attributes(cls): + """ Register the attributes of OVSPort RM + + """ + port_name = Attribute("port_name", "Name of the port", + flags = Flags.Design) + ip = Attribute("ip", "IP of the endpoint. This is the attribute " + "you should use to establish a tunnel or a remote " + "connection between endpoint", + flags = Flags.Design) + network = Attribute("network", "Network used by the port", + flags = Flags.Design) + + cls._register_attribute(port_name) + cls._register_attribute(ip) + cls._register_attribute(network) + + def __init__(self, ec, guid): + """ + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + super(PlanetlabOVSPort, self).__init__(ec, guid) + self._home = "ovsport-%s" % self.guid + self._port_number = None + + @property +
[docs] def node(self): + """ Node that run the switch and the ports + """ + return self.ovsswitch.node +
+ @property +
[docs] def ovsswitch(self): + """ Switch where the port is created + """ + ovsswitch = self.get_connected(PlanetlabOVSSwitch.get_rtype()) + if ovsswitch: return ovsswitch[0] + return None +
+ @property +
[docs] def port_number(self): + return self._port_number +
+
[docs] def valid_connection(self, guid): + """ Check if the connection is available. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + + """ + rm = self.ec.get_resource(guid) + if rm.get_rtype() not in self._authorized_connections: + return False + + return True +
+
[docs] def create_port(self): + """ Create the desired port + """ + msg = "Creating the port %s" % self.get('port_name') + self.debug(msg) + + if not self.get('port_name'): + msg = "The port name is not assigned" + self.error(msg) + raise AttributeError, msg + + if not self.ovsswitch: + msg = "The OVSwitch RM is not running" + self.error(msg) + raise AttributeError, msg + + command = "sliver-ovs create-port %s %s" % ( + self.ovsswitch.get('bridge_name'), + self.get('port_name')) + + shfile = os.path.join(self.app_home, "create_port.sh") + try: + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo = True, + stderr="port_stdout", + stdout="port_stderr", + pidfile="port_pidfile", + ecodefile="port_exitcode") + except RuntimeError: + msg = "Could not create ovs-port" + self.debug(msg) + raise RuntimeError, msg + + self.info("Created port %s on switch %s" % ( + self.get('port_name'), + self.ovsswitch.get('bridge_name'))) +
+
[docs] def initiate_udp_connection(self, remote_endpoint, connection_app_home, + connection_run_home, cipher, cipher_key, bwlimit, txqueuelen): + """ Get the local_endpoint of the port + """ + msg = "Discovering the port number for %s" % self.get('port_name') + self.info(msg) + + command = "sliver-ovs get-local-endpoint %s" % self.get('port_name') + + shfile = os.path.join(connection_app_home, "get_port.sh") + (out, err), proc = self.node.run_and_wait(command, connection_run_home, + shfile=shfile, + sudo=True, + overwrite = True, + pidfile="get_port_pidfile", + ecodefile="get_port_exitcode", + stdout="get_port_stdout", + stderr="get_port_stderr") + + if err != "": + msg = "Error retrieving the local endpoint of the port" + self.error(msg) + raise RuntimeError, msg + + if out: + self._port_number = out.strip() + + self.info("The number of the %s is %s" % (self.get('port_name'), + self.port_number)) + + # Must set a routing rule in the ovs client nodes so they know + # that the LAN can be found through the switch + if remote_endpoint.is_rm_instance("planetlab::Tap"): + self._vroute = self.ec.register_resource("planetlab::Vroute") + self.ec.set(self._vroute, "action", "add") + self.ec.set(self._vroute, "prefix", remote_endpoint.get("prefix")) + self.ec.set(self._vroute, "nexthop", remote_endpoint.get("pointopoint")) + self.ec.set(self._vroute, "network", self.get("network")) + + self.ec.register_connection(self._vroute, remote_endpoint.guid) + self.ec.deploy(guids=[self._vroute], group = self.deployment_group) + + # For debugging + msg = "Route for the tap configured" + self.debug(msg) + + return self.port_number +
+
[docs] def establish_udp_connection(self, remote_endpoint, + connection_app_home, + connection_run_home, + port): + remote_ip = remote_endpoint.node.get("ip") + command = self._establish_connection_command(port, remote_ip) + + shfile = os.path.join(connection_app_home, "connect_port.sh") + (out, err), proc = self.node.run_and_wait(command, connection_run_home, + shfile=shfile, + sudo=True, + overwrite = True, + pidfile="connect_port_pidfile", + ecodefile="connect_port_exitcode", + stdout="connect_port_stdout", + stderr="connect_port_stderr") + + # For debugging + msg = "Connection on port configured" + self.debug(msg) +
+ def _establish_connection_command(self, port, remote_ip): + """ Script to create the connection from a switch to a + remote endpoint + """ + local_port_name = self.get('port_name') + + command = ["sliver-ovs"] + command.append("set-remote-endpoint") + command.append(local_port_name) + command.append(remote_ip) + command.append(port) + command = " ".join(command) + command = self.replace_paths(command) + return command + +
[docs] def verify_connection(self, remote_endpoint, connection_app_home, + connection_run_home): + self.ovsswitch.ovs_status() +
+
[docs] def terminate_connection(self, endpoint, connection_app_home, + connection_run_home): + return True +
+
[docs] def check_status(self): + return self.node.status(self._pid, self._ppid) +
+
[docs] def do_provision(self): + self.node.mkdir(self.run_home) + + self.create_port() + end_ip = self.ovsswitch.get('virtual_ip_pref').split('/') + self.set("ip", end_ip[0]) + + #Check the status of the OVS Switch + self.ovsswitch.ovs_status() + + self.set_provisioned() +
+
[docs] def do_deploy(self): + """ Deploy the OVS port after the OVS Switch + """ + if not self.ovsswitch or self.ovsswitch.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- OVSwitch state %s " % self.ovsswitch.state ) + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + self.do_discover() + self.do_provision() + + self.set_ready() +
+
[docs] def do_release(self): + """ Delete the port on the OVSwitch. It needs to wait for the tunnel + to be released. + """ + from nepi.resources.linux.udptunnel import LinuxUdpTunnel + rm = self.get_connected(LinuxUdpTunnel.get_rtype()) + + if rm and rm[0].state < ResourceState.STOPPED: + self.ec.schedule(self.reschedule_delay, self.release) + return + + msg = "Deleting the port %s" % self.get('port_name') + self.info(msg) + + command = "sliver-ovs del_port %s" % self.get('port_name') + + shfile = os.path.join(self.app_home, "stop.sh") + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + sudo=True, + pidfile="stop_pidfile", + ecodefile="stop_exitcode", + stdout="stop_stdout", + stderr="stop_stderr") + + super(PlanetlabOVSPort, self).do_release() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/plcapi.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/plcapi.html new file mode 100644 index 00000000..0a560cba --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/plcapi.html @@ -0,0 +1,676 @@ + + + + + + + + nepi.resources.planetlab.plcapi — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.plcapi

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 functools
+import hashlib
+import socket
+import os
+import time
+import threading
+import xmlrpclib
+
+def _retry(fn):
+    def rv(*p, **kw):
+        for x in xrange(5):
+            try:
+                return fn(*p, **kw)
+            except (socket.error, IOError, OSError):
+                time.sleep(x*5+5)
+        else:
+            return fn (*p, **kw)
+    return rv
+
+
[docs]class PLCAPI(object): + + _expected_methods = set( + ['AddNodeTag', 'AddConfFile', 'DeletePersonTag', 'AddNodeType', + 'DeleteBootState', 'SliceListNames', 'DeleteKey','SliceGetTicket', + 'SliceUsersList', 'SliceUpdate', 'GetNodeGroups', 'SliceCreate', + 'GetNetworkMethods', 'GetNodeFlavour', 'DeleteNode', 'BootNotifyOwners', + 'AddPersonKey', 'AddNode', 'UpdateNodeGroup', 'GetAddressTypes', + 'AddIlink', 'DeleteNetworkType', 'GetInitScripts', 'GenerateNodeConfFile', + 'AddSite', 'BindObjectToPeer', 'SliceListUserSlices', 'GetPeers', + 'AddPeer', 'DeletePeer', 'AddRole', 'DeleteRole', 'SetPersonPrimarySite', + 'AddSiteAddress', 'SliceDelete', 'NotifyPersons', 'GetKeyTypes', + 'GetConfFiles', 'GetIlinks', 'AddTagType', 'GetNodes', 'DeleteNodeTag', + 'DeleteSliceFromNodesWhitelist', 'UpdateAddress', 'ResetPassword', + 'AddSliceToNodesWhitelist', 'AddRoleToTagType', 'AddLeases', + 'GetAddresses', 'AddInitScript', 'RebootNode', 'GetPCUTypes', + 'RefreshPeer', 'GetBootMedium', 'UpdateKey', 'UpdatePCU', 'GetSession', + 'AddInterfaceTag', 'UpdatePCUType', 'GetInterfaces', 'SliceExtendedInfo', + 'SliceNodesList', 'DeleteRoleFromTagType', 'DeleteSlice', 'GetSites', + 'DeleteMessage', 'GetSliceFamily', 'GetPlcRelease', 'UpdateTagType', + 'AddSliceInstantiation', 'ResolveSlices', 'GetSlices', + 'DeleteRoleFromPerson', 'GetSessions', 'UpdatePeer', 'VerifyPerson', + 'GetPersonTags', 'DeleteKeyType', 'AddSlice', 'SliceUserAdd', + 'DeleteSession', 'GetMessages', 'DeletePCU', 'GetPeerData', + 'DeletePersonFromSite', 'DeleteTagType', 'GetPCUs', 'UpdateLeases', + 'AddMessage', 'DeletePCUProtocolType', 'DeleteInterfaceTag', + 'AddPersonToSite', 'GetSlivers', 'SliceNodesDel', + 'DeleteAddressTypeFromAddress', 'AddNodeGroup', 'GetSliceTags', + 'DeleteSite', 'GetSiteTags', 'UpdateMessage', 'DeleteSliceFromNodes', + 'SliceRenew', 'UpdatePCUProtocolType', 'DeleteSiteTag', + 'GetPCUProtocolTypes', 'GetEvents', 'GetSliceTicket', 'AddPersonTag', + 'BootGetNodeDetails', 'DeleteInterface', 'DeleteNodeGroup', + 'AddPCUProtocolType', 'BootCheckAuthentication', 'AddSiteTag', + 'AddAddressTypeToAddress', 'DeleteConfFile', 'DeleteInitScript', + 'DeletePerson', 'DeleteIlink', 'DeleteAddressType', 'AddBootState', + 'AuthCheck', 'NotifySupport', 'GetSliceInstantiations', 'AddPCUType', + 'AddPCU', 'AddSession', 'GetEventObjects', 'UpdateSiteTag', + 'UpdateNodeTag', 'AddPerson', 'BlacklistKey', 'UpdateInitScript', + 'AddSliceToNodes', 'RebootNodeWithPCU', 'GetNodeTags', 'GetSliceKeys', + 'GetSliceSshKeys', 'AddNetworkMethod', 'SliceNodesAdd', + 'DeletePersonFromSlice', 'ReportRunlevel', 'GetNetworkTypes', + 'UpdateSite', 'DeleteConfFileFromNodeGroup', 'UpdateNode', + 'DeleteSliceInstantiation', 'DeleteSliceTag', 'BootUpdateNode', + 'UpdatePerson', 'UpdateConfFile', 'SliceUserDel', 'DeleteLeases', + 'AddConfFileToNodeGroup', 'UpdatePersonTag', 'DeleteConfFileFromNode', + 'AddPersonToSlice', 'UnBindObjectFromPeer', 'AddNodeToPCU', + 'GetLeaseGranularity', 'DeletePCUType', 'GetTagTypes', 'GetNodeTypes', + 'UpdateInterfaceTag', 'GetRoles', 'UpdateSlice', 'UpdateSliceTag', + 'AddSliceTag', 'AddNetworkType', 'AddInterface', 'AddAddressType', + 'AddRoleToPerson', 'DeleteNodeType', 'GetLeases', 'UpdateInterface', + 'SliceInfo', 'DeleteAddress', 'SliceTicketGet', 'GetPersons', + 'GetWhitelist', 'AddKeyType', 'UpdateAddressType', 'GetPeerName', + 'DeleteNetworkMethod', 'UpdateIlink', 'AddConfFileToNode', 'GetKeys', + 'DeleteNodeFromPCU', 'GetInterfaceTags', 'GetBootStates', + 'SetInterfaceSens', 'SetNodeLoadm', 'GetInterfaceRate', 'GetNodeLoadw', + 'SetInterfaceKey', 'GetNodeSlices', 'GetNodeLoadm', 'SetSliceVref', + 'GetInterfaceIwpriv', 'SetNodeLoadw', 'SetNodeSerial', + 'GetNodePlainBootstrapfs', 'SetNodeMEMw', 'GetNodeResponse', + 'SetInterfaceRate', 'SetSliceInitscript', 'SetNodeFcdistro', + 'GetNodeLoady', 'SetNodeArch', 'SetNodeKargs', 'SetNodeMEMm', + 'SetNodeBWy', 'SetNodeBWw', 'SetInterfaceSecurityMode', 'SetNodeBWm', + 'SetNodeASType', 'GetNodeKargs', 'GetPersonColumnconf', + 'GetNodeResponsem', 'GetNodeCPUy', 'GetNodeCramfs', 'SetNodeSlicesw', + 'SetPersonColumnconf', 'SetNodeSlicesy', 'GetNodeCPUw', 'GetNodeBWy', + 'GetNodeCPUm', 'GetInterfaceDriver', 'GetNodeLoad', 'GetInterfaceMode', + 'GetNodeSerial', 'SetNodeSlicesm', 'SetNodeLoady', 'GetNodeReliabilityw', + 'SetSliceFcdistro', 'GetNodeReliabilityy', 'SetInterfaceEssid', + 'SetSliceInitscriptCode', 'GetNodeExtensions', 'GetSliceOmfControl', + 'SetNodeCity', 'SetInterfaceIfname', 'SetNodeHrn', 'SetNodeNoHangcheck', + 'GetNodeNoHangcheck', 'GetSliceFcdistro', 'SetNodeCountry', + 'SetNodeKvariant', 'GetNodeKvariant', 'GetNodeMEMy', 'SetInterfaceIwpriv', + 'GetNodeMEMw', 'SetInterfaceBackdoor', 'GetInterfaceFreq', + 'SetInterfaceChannel', 'SetInterfaceNw', 'GetPersonShowconf', + 'GetSliceInitscriptCode', 'SetNodeMEM', 'GetInterfaceEssid', 'GetNodeMEMm', + 'SetInterfaceMode', 'SetInterfaceIwconfig', 'GetNodeSlicesm', 'GetNodeBWm', + 'SetNodePlainBootstrapfs', 'SetNodeRegion', 'SetNodeCPU', 'GetNodeSlicesw', + 'SetNodeBW', 'SetNodeSlices', 'SetNodeCramfs', 'GetNodeSlicesy', + 'GetInterfaceKey', 'GetSliceInitscript', 'SetNodeCPUm', 'SetSliceArch', + 'SetNodeLoad', 'SetNodeResponse', 'GetSliceSliverHMAC', 'GetNodeBWw', + 'GetNodeRegion', 'SetNodeMEMy', 'GetNodeASType', 'SetNodePldistro', + 'GetSliceArch', 'GetNodeCountry', 'SetSliceOmfControl', 'GetNodeHrn', + 'GetNodeCity', 'SetInterfaceAlias', 'GetNodeBW', 'GetNodePldistro', + 'GetSlicePldistro', 'SetNodeASNumber', 'GetSliceHmac', 'SetSliceHmac', + 'GetNodeMEM', 'GetNodeASNumber', 'GetInterfaceAlias', 'GetSliceVref', + 'GetNodeArch', 'GetSliceSshKey', 'GetInterfaceKey4', 'GetInterfaceKey2', + 'GetInterfaceKey3', 'GetInterfaceKey1', 'GetInterfaceBackdoor', + 'GetInterfaceIfname', 'SetSliceSliverHMAC', 'SetNodeReliability', + 'GetNodeCPU', 'SetPersonShowconf', 'SetNodeExtensions', 'SetNodeCPUy', + 'SetNodeCPUw', 'GetNodeResponsew', 'SetNodeResponsey', 'GetInterfaceSens', + 'SetNodeResponsew', 'GetNodeResponsey', 'GetNodeReliability', + 'GetNodeReliabilitym', 'SetNodeResponsem', 'SetInterfaceDriver', + 'GetInterfaceSecurityMode', 'SetNodeDeployment', 'SetNodeReliabilitym', + 'GetNodeFcdistro', 'SetInterfaceFreq', 'GetInterfaceNw', + 'SetNodeReliabilityy', 'SetNodeReliabilityw', 'GetInterfaceIwconfig', + 'SetSlicePldistro', 'SetSliceSshKey', 'GetNodeDeployment', + 'GetInterfaceChannel', 'SetInterfaceKey2', 'SetInterfaceKey3', + 'SetInterfaceKey1', 'SetInterfaceKey4']) + + _required_methods = set() + + 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) + elif username is not None and password is not None: + self.auth = dict(AuthMethod='password', Username=username, AuthString=password) + else: + self.auth = dict(AuthMethod='anonymous') + + self._local_peer = local_peer + self._url = urlpattern % {'hostname':hostname} + + if (proxy is not None): + import urllib2 + class HTTPSProxyTransport(xmlrpclib.Transport): + def __init__(self, proxy, use_datetime=0): + opener = urllib2.build_opener(urllib2.ProxyHandler({"https" : proxy})) + xmlrpclib.Transport.__init__(self, use_datetime) + self.opener = opener + + def request(self, host, handler, request_body, verbose=0): + req = urllib2.Request('https://%s%s' % (host, handler), request_body) + req.add_header('User-agent', self.user_agent) + self.verbose = verbose + return self.parse_response(self.opener.open(req)) + + self._proxy_transport = lambda : HTTPSProxyTransport(proxy) + else: + self._proxy_transport = lambda : None + + self.threadlocal = threading.local() + + # Load blacklist from file + if self._ecobj.get_global('planetlab::Node', 'persist_blacklist'): + self._set_blacklist() + + @property +
[docs] def api(self): + # Cannot reuse same proxy in all threads, py2.7 is not threadsafe + return xmlrpclib.ServerProxy( + self._url , + transport = self._proxy_transport(), + allow_none = True) +
+ @property +
[docs] def mcapi(self): + try: + return self.threadlocal.mc + except AttributeError: + return self.api +
+
[docs] def test(self): + # TODO: Use nepi utils Logger instead of warning!! + import warnings + + # validate XMLRPC server checking supported API calls + methods = set(_retry(self.mcapi.system.listMethods)()) + if self._required_methods - methods: + warnings.warn("Unsupported REQUIRED methods: %s" % ( + ", ".join(sorted(self._required_methods - methods)), ) ) + return False + + if self._expected_methods - methods: + warnings.warn("Unsupported EXPECTED methods: %s" % ( + ", ".join(sorted(self._expected_methods - methods)), ) ) + + try: + # test authorization + network_types = _retry(self.mcapi.GetNetworkTypes)(self.auth) + except (xmlrpclib.ProtocolError, xmlrpclib.Fault),e: + 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 +
[docs] def network_types(self): + try: + return self._network_types + except AttributeError: + self._network_types = _retry(self.mcapi.GetNetworkTypes)(self.auth) + return self._network_types +
+ @property +
[docs] def peer_map(self): + try: + return self._peer_map + except AttributeError: + peers = _retry(self.mcapi.GetPeers)(self.auth, {}, ['shortname','peername','peer_id']) + + self._peer_map = dict( + (peer['shortname'], peer['peer_id']) + for peer in peers + ) + + self._peer_map.update( + (peer['peername'], peer['peer_id']) + for peer in peers + ) + + self._peer_map.update( + (peer['peer_id'], peer['shortname']) + for peer in peers + ) + + self._peer_map[None] = self._local_peer + return self._peer_map +
+
[docs] def get_node_flavour(self, node): + """ + Returns detailed information on a given node's flavour, + i.e. its base installation. + + This depends on the global PLC settings in the PLC_FLAVOUR area, + optionnally overridden by any of the following tags if set on that node: + 'arch', 'pldistro', 'fcdistro', 'deployment', 'extensions' + + Params: + + * node : int or string + - int, Node identifier + - string, Fully qualified hostname + + Returns: + + struct + * extensions : array of string, extensions to add to the base install + * fcdistro : string, the fcdistro this node should be based upon + * nodefamily : string, the nodefamily this node should be based upon + * plain : boolean, use plain bootstrapfs image if set (for tests) + """ + if not isinstance(node, (str, int, long)): + raise ValueError, "Node must be either a non-unicode string or an int" + return _retry(self.mcapi.GetNodeFlavour)(self.auth, node) +
+
[docs] def get_nodes(self, node_id_or_name = None, fields = None, **kw): + """ + Returns an array of structs containing details about nodes. + If node_id_or_name is specified and is an array of node identifiers + or hostnames, or the filters keyword argument with struct of node + attributes, or node attributes by keyword argument, + only nodes matching the filter will be returned. + + If fields is specified, only the specified details will be returned. + NOTE that if fields is unspecified, the complete set of native fields are + returned, which DOES NOT include tags at this time. + + Some fields may only be viewed by admins. + + Special params: + + fields: an optional list of fields to retrieve. The default is all. + + filters: an optional mapping with custom filters, which is the only + way to support complex filters like negation and numeric comparisons. + + peer: a string (or sequence of strings) with the name(s) of peers + to filter - or None for local nodes. + """ + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if node_id_or_name is not None: + return _retry(self.mcapi.GetNodes)(self.auth, node_id_or_name, *fieldstuple) + else: + filters = kw.pop('filters',{}) + + if 'peer' in kw: + peer = kw.pop('peer') + + name_to_id = self.peer_map.get + + if hasattr(peer, '__iter__'): + # we can't mix local and external nodes, so + # split and re-issue recursively in that case + if None in peer or self._local_peer in peer: + if None in peer: + peer.remove(None) + + if self._local_peer in peer: + peer.remove(self._local_peer) + + return ( + self.get_nodes(node_id_or_name, fields, + filters = filters, peer=peer, **kw) + \ + self.get_nodes(node_id_or_name, fields, + filters = filters, peer=None, **kw) + ) + else: + peer_filter = map(name_to_id, peer) + + elif peer is None or peer == self._local_peer: + peer_filter = None + else: + peer_filter = name_to_id(peer) + + filters['peer_id'] = peer_filter + + filters.update(kw) + + if not filters and not fieldstuple: + if not self._nodes_cache and not self._already_cached: + self._already_cached = True + self._nodes_cache = _retry(self.mcapi.GetNodes)(self.auth) + elif not self._nodes_cache: + while not self._nodes_cache: + time.sleep(10) + return self._nodes_cache + + return _retry(self.mcapi.GetNodes)(self.auth, filters, *fieldstuple) +
+
[docs] def get_node_tags(self, node_tag_id = None, fields = None, **kw): + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if node_tag_id is not None: + return _retry(self.mcapi.GetNodeTags)(self.auth, node_tag_id, + *fieldstuple) + else: + filters = kw.pop('filters',{}) + filters.update(kw) + return _retry(self.mcapi.GetNodeTags)(self.auth, filters, + *fieldstuple) +
+
[docs] def get_slice_tags(self, slice_tag_id = None, fields = None, **kw): + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if slice_tag_id is not None: + return _retry(self.mcapi.GetSliceTags)(self.auth, slice_tag_id, + *fieldstuple) + else: + filters = kw.pop('filters',{}) + filters.update(kw) + return _retry(self.mcapi.GetSliceTags)(self.auth, filters, + *fieldstuple) +
+
[docs] def get_interfaces(self, interface_id_or_ip = None, fields = None, **kw): + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if interface_id_or_ip is not None: + return _retry(self.mcapi.GetInterfaces)(self.auth, + interface_id_or_ip, *fieldstuple) + else: + filters = kw.pop('filters',{}) + filters.update(kw) + return _retry(self.mcapi.GetInterfaces)(self.auth, filters, + *fieldstuple) +
+
[docs] def get_slices(self, slice_id_or_name = None, fields = None, **kw): + if fields is not None: + fieldstuple = (fields,) + else: + fieldstuple = () + + if slice_id_or_name is not None: + return _retry(self.mcapi.GetSlices)(self.auth, slice_id_or_name, + *fieldstuple) + else: + filters = kw.pop('filters',{}) + filters.update(kw) + return _retry(self.mcapi.GetSlices)(self.auth, filters, + *fieldstuple) +
+
[docs] def update_slice(self, slice_id_or_name, **kw): + return _retry(self.mcapi.UpdateSlice)(self.auth, slice_id_or_name, kw) +
+
[docs] def delete_slice_node(self, slice_id_or_name, node_id_or_hostname): + return _retry(self.mcapi.DeleteSliceFromNodes)(self.auth, slice_id_or_name, node_id_or_hostname) +
+
[docs] def start_multicall(self): + self.threadlocal.mc = xmlrpclib.MultiCall(self.mcapi) +
+
[docs] def finish_multicall(self): + mc = self.threadlocal.mc + del self.threadlocal.mc + return _retry(mc)() +
+
[docs] def get_slice_nodes(self, slicename): + return self.get_slices(slicename, ['node_ids'])[0]['node_ids'] +
+
[docs] def add_slice_nodes(self, slicename, nodes): + self.update_slice(slicename, nodes=nodes) +
+
[docs] def get_node_info(self, node_id): + self.start_multicall() + info = self.get_nodes(node_id) + tags = self.get_node_tags(node_id=node_id, fields=('tagname','value')) + info, tags = self.finish_multicall() + return info, tags +
+
[docs] def get_slice_id(self, slicename): + slice_id = None + slices = self.get_slices(slicename, fields=('slice_id',)) + if slices: + slice_id = slices[0]['slice_id'] + + # If it wasn't found, don't remember this failure, keep trying + return slice_id +
+
[docs] def get_slice_vnet_sys_tag(self, slicename): + slicetags = self.get_slice_tags( + name = slicename, + tagname = 'vsys_vnet', + fields=('value',)) + + if slicetags: + return slicetags[0]['value'] + else: + return None +
+
[docs] def blacklist_host(self, node_id): + self._blacklist.add(node_id) +
+
[docs] def blacklisted(self): + return self._blacklist +
+
[docs] def unblacklist_host(self, node_id): + del self._blacklist[node_id] +
+
[docs] def reserve_host(self, node_id): + self._reserved.add(node_id) +
+
[docs] def reserved(self): + return self._reserved +
+
[docs] def unreserve_host(self, node_id): + del self._reserved[node_id] +
+
[docs] def release(self): + self.count -= 1 + if self.count == 0: + blacklist = self._blacklist + self._blacklist = set() + self._reserved = set() + if self._ecobj.get_global('PlanetlabNode', 'persist_blacklist'): + if blacklist: + to_blacklist = list() + hostnames = self.get_nodes(list(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) + +
+
[docs]class PLCAPIFactory(object): + """ + .. note:: + + It allows PlanetLab RMs sharing a same slice, to use a same plcapi instance, + and to sincronize blacklisted and reserved hosts. + + """ + # use lock to avoid concurrent access to the Api list at the same times by 2 different threads + _lock = threading.Lock() + _apis = dict() + + @classmethod +
[docs] def get_api(cls, pl_user, pl_pass, pl_host, + pl_ptn, ec, proxy = None): + """ Get existing PLCAPI instance + + :param pl_user: Planelab user name (used for web login) + :type pl_user: str + :param pl_pass: Planetlab password (used for web login) + :type pl_pass: str + :param pl_host: Planetlab registry host (e.g. "www.planet-lab.eu") + :type pl_host: str + :param pl_ptn: XMLRPC service pattern (e.g. https://%(hostname)s:443/PLCAPI/) + :type pl_ptn: str + :param proxy: Proxy service url + :type pl_ptn: str + """ + if pl_user and pl_pass and pl_host: + key = cls._make_key(pl_user, pl_host) + with cls._lock: + api = cls._apis.get(key) + if not api: + api = cls.create_api(pl_user, pl_pass, pl_host, pl_ptn, ec, proxy) + else: + api.count += 1 + return api + return None +
+ @classmethod +
[docs] def create_api(cls, pl_user, pl_pass, pl_host, + pl_ptn, ec, proxy = None): + """ Create an PLCAPI instance + + :param pl_user: Planelab user name (used for web login) + :type pl_user: str + :param pl_pass: Planetlab password (used for web login) + :type pl_pass: str + :param pl_host: Planetlab registry host (e.g. "www.planet-lab.eu") + :type pl_host: str + :param pl_ptn: XMLRPC service pattern (e.g. https://%(hostname)s:443/PLCAPI/) + :type pl_ptn: str + :param proxy: Proxy service url + :type pl_ptn: str + """ + 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 +
+ @classmethod + def _make_key(cls, *args): + """ Hash the credentials in order to create a key + + :param args: list of arguments used to create the hash (user, host, port, ...) + :type args: list of args + + """ + skey = "".join(map(str, args)) + return hashlib.md5(skey).hexdigest() +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/sfa_node.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/sfa_node.html new file mode 100644 index 00000000..772422c1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/sfa_node.html @@ -0,0 +1,762 @@ + + + + + + + + nepi.resources.planetlab.sfa_node — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.sfa_node

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+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 os
+import weakref
+import time
+import socket
+import threading
+import datetime
+
+@clsinit_copy
+
[docs]class PlanetlabSfaNode(LinuxNode): + _rtype = "planetlab::sfa::Node" + _help = "Controls a PlanetLab host accessible using a SSH key " \ + "and provisioned using SFA" + _platform = "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) + + # 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() + + def _skip_provision(self): + sfa_user = self.get("sfauser") + if not sfa_user: + return True + else: return False + + @property +
[docs] def sfaapi(self): + """ + Property to instanciate the SFA API based in sfi client. + For each SFA method called this instance is used. + """ + 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() +
+
[docs] 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) and 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.debug("The node %s is already in the slice" % hostname) + self._slicenode = True + self._node_to_provision = host_hrn + else: + self.fail_node_not_available(hostname) + super(PlanetlabSfaNode, self).do_discover() + + else: + hosts_hrn = nodes.values() + nodes_inslice = self._check_if_in_slice(hosts_hrn) + nodes_not_inslice = list(set(hosts_hrn) - set(nodes_inslice)) + host_hrn = None + if nodes_inslice: + host_hrn = self._choose_random_node(nodes, nodes_inslice) + self._slicenode = True + + if not host_hrn: + # 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 + host_hrn = self._choose_random_node(nodes, nodes_not_inslice) + self._slicenode = False + + if host_hrn: + self._node_to_provision = host_hrn + try: + self._set_hostname_attr(host_hrn) + self.info(" Selected node to provision ") + super(PlanetlabSfaNode, self).do_discover() + except: + self._blacklist_node(host_hrn) + self.do_discover() + else: + self.fail_not_enough_nodes() +
+ def _blacklisted(self, host_hrn): + """ + Check in the SFA API that the node is not in the blacklist. + """ + if self.sfaapi.blacklisted(host_hrn): + return True + return False + + def _reserved(self, host_hrn): + """ + Check in the SFA API that the node is not in the reserved + list. + """ + if self.sfaapi.reserved(host_hrn): + return True + return False + +
[docs] def do_provision(self): + """ + Add node to user's slice and verifing that the node is functioning + correctly. Check ssh, file system. + """ + 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.warning(" 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.warning(" 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() +
+
[docs] def do_release(self): + super(PlanetlabSfaNode, self).do_release() + if self.state == ResourceState.RELEASED and not self._skip_provision(): + self.debug(" Releasing SFA API ") + self.sfaapi.release() + +# 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, hosts_hrn): + """ + From the possible nodes for provision, choose randomly to decrese the + probability of different RMs choosing the same node for provision + """ + size = len(hosts_hrn) + while size: + size = size - 1 + index = randint(0, size) + host_hrn = hosts_hrn[index] + hosts_hrn[index] = hosts_hrn[size] + + # check the node is not blacklisted or being provision by other RM + # and perform ping to check that is really alive + if not self._blacklisted(host_hrn): + if not self._reserved(host_hrn): + print self.sfaapi._reserved ,self.guid + for hostname, hrn in nodes.iteritems(): + if host_hrn == hrn: + print 'hostname' ,hostname + ping_ok = self._do_ping(hostname) + + if not ping_ok: + self._set_hostname_attr(hostname) + self.warning(" Node not responding PING ") + self._blacklist_node(host_hrn) + else: + # discovered node for provision, added to provision list + self._node_to_provision = host_hrn + return host_hrn + +# def _get_nodes_id(self, filters=None): +# return self.plapi.get_nodes(filters, fields=['node_id']) +# + def _add_node_to_slice(self, host_hrn): + """ + Add node to slice, using SFA API. + """ + 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_from_slice(self): + """ + Delete every node from slice, using SFA API. + Sfi client doesn't work for particular node urns. + """ + self.warning(" Deleting node from slice ") + slicename = self.get("username").replace('_', '.') + slicename = 'ple.' + slicename + self.sfaapi.remove_all_from_slice(slicename) + + def _get_hostname(self): + """ + Get the attribute hostname. + """ + 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'] + if slice_nodes: + slice_nodes_hrn = self.sfaapi.get_resources_hrn(slice_nodes).values() + else: slice_nodes_hrn = [] + nodes_inslice = list(set(hosts_hrn) & set(slice_nodes_hrn)) + 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 mal functioning node to blacklist (in SFA API). + """ + 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 + +
[docs] def fail_discovery(self): + msg = "Discovery failed. No candidates found for node" + self.error(msg) + raise RuntimeError, msg +
+
[docs] def fail_node_not_alive(self, hostname=None): + msg = "Node %s not alive" % hostname + raise RuntimeError, msg +
+
[docs] def fail_node_not_available(self, hostname): + msg = "Node %s not available for provisioning" % hostname + raise RuntimeError, msg +
+
[docs] def fail_not_enough_nodes(self): + msg = "Not enough nodes available for provisioning" + raise RuntimeError, msg +
+
[docs] def fail_sfaapi(self): + msg = "Failing while trying to instanciate the SFA API.\nSet the" + \ + " attributes sfauser and sfaPrivateKey." + raise RuntimeError, msg +
+
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tap.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tap.html new file mode 100644 index 00000000..9b0791ce --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tap.html @@ -0,0 +1,413 @@ + + + + + + + + nepi.resources.planetlab.tap — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.tap

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 
+from nepi.resources.linux.tap import LinuxTap
+from nepi.resources.planetlab.node import PlanetlabNode
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+import time
+
+PYTHON_VSYS_VERSION = "1.0"
+
+@clsinit_copy
+
[docs]class PlanetlabTap(LinuxTap): + _rtype = "planetlab::Tap" + _help = "Creates a TAP device on a PlanetLab host" + _platform = "planetlab" + + @classmethod + def _register_attributes(cls): + snat = Attribute("snat", "Set SNAT=1", + type = Types.Bool, + flags = Flags.Design) + + cls._register_attribute(snat) + + def __init__(self, ec, guid): + super(PlanetlabTap, self).__init__(ec, guid) + self._home = "tap-%s" % self.guid + self._gre_enabled = False + + @property +
[docs] def node(self): + node = self.get_connected(PlanetlabNode.get_rtype()) + if node: return node[0] + raise RuntimeError, "TAP/TUN devices must be connected to Node" +
+
[docs] def upload_sources(self): + scripts = [] + + # vif-creation python script + pl_vif_create = os.path.join(os.path.dirname(__file__), "scripts", + "pl-vif-create.py") + + scripts.append(pl_vif_create) + + # vif-up python script + pl_vif_up = os.path.join(os.path.dirname(__file__), "scripts", + "pl-vif-up.py") + + scripts.append(pl_vif_up) + + # vif-down python script + pl_vif_down = os.path.join(os.path.dirname(__file__), "scripts", + "pl-vif-down.py") + + scripts.append(pl_vif_down) + + # udp-connect python script + udp_connect = os.path.join(os.path.dirname(__file__), + "..", + "linux", + "scripts", + "linux-udp-connect.py") + + scripts.append(udp_connect) + + # tunnel creation python script + tunchannel = os.path.join(os.path.dirname(__file__), + "..", + "linux", + "scripts", + "tunchannel.py") + + scripts.append(tunchannel) + + # Upload scripts + scripts = ";".join(scripts) + + self.node.upload(scripts, + os.path.join(self.node.src_dir), + overwrite = False) + + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + + self.node.upload_command(stop_command, + shfile = os.path.join(self.app_home, "stop.sh"), + # Overwrite file every time. + # The stop.sh has the path to the socket, which should change + # on every experiment run. + overwrite = True) +
+
[docs] def upload_start_command(self): + super(PlanetlabTap, self).upload_start_command() + + # Planetlab TAPs always add a PI header + self.set("pi", True) + + if not self.gre_enabled: + # After creating the TAP, the pl-vif-create.py script + # will write the name of the TAP to a file. We wait until + # we can read the interface name from the file. + vif_name = self.wait_vif_name() + self.set("deviceName", vif_name) +
+
[docs] def wait_vif_name(self, exec_run_home = None): + """ Waits until the vif_name file for the command is generated, + and returns the vif_name for the device """ + vif_name = None + delay = 0.5 + + # The vif_name file will be created in the tap-home, while the + # current execution home might be elsewhere to check for errors + # (e.g. could be a tunnel-home) + if not exec_run_home: + exec_run_home = self.run_home + + for i in xrange(20): + (out, err), proc = self.node.check_output(self.run_home, "vif_name") + + if proc.poll() > 0: + (out, err), proc = self.node.check_errors(exec_run_home) + + if err.strip(): + raise RuntimeError, err + + if out: + vif_name = out.strip() + break + else: + time.sleep(delay) + delay = delay * 1.5 + else: + msg = "Couldn't retrieve vif_name" + self.error(msg, out, err) + raise RuntimeError, msg + + return vif_name +
+
[docs] def gre_connect(self, remote_endpoint, connection_app_home, + connection_run_home): + super(PlanetlabTap, self).gre_connect(remote_endpoint, + connection_app_home, connection_run_home) + # After creating the TAP, the pl-vif-create.py script + # will write the name of the TAP to a file. We wait until + # we can read the interface name from the file. + vif_name = self.wait_vif_name(exec_run_home = connection_run_home) + self.set("deviceName", vif_name) + + return True +
+ def _gre_connect_command(self, remote_endpoint, connection_app_home, + connection_run_home): + # Set the remote endpoint, (private) IP of the device + self.set("pointopoint", remote_endpoint.get("ip")) + # Public IP of the node + self.set("greRemote", remote_endpoint.node.get("ip")) + + # Generate GRE connect command + + # Use vif_down command to first kill existing TAP in GRE mode + vif_down_command = self._vif_down_command + + # Use pl-vif-up.py script to configure TAP with peer info + vif_up_command = self._vif_up_command + + command = ["("] + command.append(vif_down_command) + command.append(") ; (") + command.append(vif_up_command) + command.append(")") + + command = " ".join(command) + command = self.replace_paths(command) + + return command + + @property + def _start_command(self): + if self.gre_enabled: + command = [] + else: + command = ["sudo -S python ${SRC}/pl-vif-create.py"] + + command.append("-t %s" % self.vif_type) + command.append("-a %s" % self.get("ip")) + command.append("-n %s" % self.get("prefix")) + command.append("-f %s " % self.vif_name_file) + command.append("-S %s " % self.sock_name) + + if self.get("snat") == True: + command.append("-s") + + if self.get("pointopoint"): + command.append("-p %s" % self.get("pointopoint")) + + if self.get("txqueuelen"): + command.append("-q %s" % self.get("txqueuelen")) + + return " ".join(command) + + @property + def _stop_command(self): + if self.gre_enabled: + command = self._vif_down_command + else: + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/pl-vif-down.py") + command.append("-S %s " % self.sock_name) + command = " ".join(command) + + return command + + @property + def _vif_up_command(self): + if self.gre_enabled: + device_name = "%s" % self.guid + else: + device_name = self.get("deviceName") + + # Use pl-vif-up.py script to configure TAP + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/pl-vif-up.py") + command.append("-u %s" % self.node.get("username")) + command.append("-N %s" % device_name) + command.append("-t %s" % self.vif_type) + command.append("-a %s" % self.get("ip")) + command.append("-n %s" % self.get("prefix")) + + if self.get("snat") == True: + command.append("-s") + + if self.get("pointopoint"): + command.append("-p %s" % self.get("pointopoint")) + + if self.get("txqueuelen"): + command.append("-q %s" % self.get("txqueuelen")) + + if self.gre_enabled: + command.append("-g %s" % self.get("greKey")) + command.append("-G %s" % self.get("greRemote")) + + command.append("-f %s " % self.vif_name_file) + + return " ".join(command) + + @property + def _vif_down_command(self): + if self.gre_enabled: + device_name = "%s" % self.guid + else: + device_name = self.get("deviceName") + + command = ["sudo -S "] + command.append("PYTHONPATH=$PYTHONPATH:${SRC}") + command.append("python ${SRC}/pl-vif-down.py") + command.append("-N %s " % device_name) + + if self.gre_enabled: + command.append("-u %s" % self.node.get("username")) + command.append("-t %s" % self.vif_type) + command.append("-D") + + return " ".join(command) + + @property +
[docs] def vif_name_file(self): + return os.path.join(self.run_home, "vif_name") +
+ @property + def _install(self): + # Install python-vsys and python-passfd + install_vsys = ( " ( " + " python -c 'import vsys, os; vsys.__version__ == \"%(version)s\" or os._exit(1)' " + " ) " + " || " + " ( " + " cd ${SRC} ; " + " hg clone http://nepi.inria.fr/code/python-vsys ; " + " cd python-vsys ; " + " make all ; " + " sudo -S make install " + " )" ) % ({ + "version": PYTHON_VSYS_VERSION + }) + + install_passfd = ( " ( python -c 'import passfd' ) " + " || " + " ( " + " cd ${SRC} ; " + " hg clone http://nepi.inria.fr/code/python-passfd ; " + " cd python-passfd ; " + " make all ; " + " sudo -S make install " + " )" ) + + return "%s ; %s" % ( install_vsys, install_passfd ) + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tun.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tun.html new file mode 100644 index 00000000..c77c0bb3 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/tun.html @@ -0,0 +1,129 @@ + + + + + + + + nepi.resources.planetlab.tun — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.tun

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.planetlab.tap import PlanetlabTap
+from nepi.resources.linux.tap import LinuxTap
+
+import os
+
+@clsinit_copy
+
[docs]class PlanetlabTun(PlanetlabTap): + _rtype = "planetlab::Tun" + _help = "Creates a TUN device on a PlanetLab host" + _platform = "planetlab" + + def __init__(self, ec, guid): + super(PlanetlabTun, self).__init__(ec, guid) + self._vif_prefix = "tun" + self._vif_type = "IFF_TUN" + self._vif_type_flag = LinuxTap.IFF_TUN + self._home = "%s-%s" % (self.vif_prefix, self.guid) + +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/vroute.html b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/vroute.html new file mode 100644 index 00000000..e75ef011 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/resources/planetlab/vroute.html @@ -0,0 +1,276 @@ + + + + + + + + nepi.resources.planetlab.vroute — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.resources.planetlab.vroute

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 
+from nepi.resources.linux.application import LinuxApplication
+from nepi.resources.planetlab.node import PlanetlabNode
+from nepi.resources.planetlab.tap import PlanetlabTap
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+import time
+
+PYTHON_VSYS_VERSION = "1.0"
+
+@clsinit_copy
+
[docs]class PlanetlabVroute(LinuxApplication): + _rtype = "planetlab::Vroute" + _help = "Creates a Vroute on a PlanetLab host" + _platform = "planetlab" + + @classmethod + def _register_attributes(cls): + action = Attribute("action", "Either add or del", + allowed = ["add", "del"], + default = "add", + flags = Flags.Design) + + prefix = Attribute("prefix", "IPv4 Prefix", + flags = Flags.Design) + + nexthop = Attribute("nexthop", "IPv4 Address of the next hop", + flags = Flags.Design) + + network = Attribute("network", "IPv4 Network Address", + flags = Flags.Design) + + cls._register_attribute(action) + cls._register_attribute(prefix) + cls._register_attribute(nexthop) + cls._register_attribute(network) + + def __init__(self, ec, guid): + super(PlanetlabVroute, self).__init__(ec, guid) + self._home = "vroute-%s" % self.guid + + @property +
[docs] def tap(self): + tap = self.get_connected(PlanetlabTap.get_rtype()) + if tap: return tap[0] + return None +
+ @property +
[docs] def node(self): + node = self.tap.get_connected(PlanetlabNode.get_rtype()) + if node: return node[0] + return None +
+
[docs] def upload_sources(self): + # upload vif-creation python script + pl_vroute = os.path.join(os.path.dirname(__file__), + "scripts", + "pl-vroute.py") + + self.node.upload(pl_vroute, + os.path.join(self.node.src_dir, "pl-vroute.py"), + overwrite = False) + + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + self.node.upload(stop_command, + os.path.join(self.app_home, "stop.sh"), + text = True, + # Overwrite file every time. + # The stop.sh has the path to the socket, wich should change + # on every experiment run. + overwrite = True) +
+
[docs] def upload_start_command(self): + # Overwrite file every time. + # The stop.sh has the path to the socket, wich should change + # on every experiment run. + command = self.get("command") + shfile = os.path.join(self.app_home, "start.sh") + self.node.run_and_wait(command, self.run_home, + shfile=shfile, + overwrite=True) +
+
[docs] def do_deploy(self): + if not self.tap or self.tap.state < ResourceState.PROVISIONED: + self.ec.schedule(self.reschedule_delay, self.deploy) + else: + if not self.get("command"): + self.set("command", self._start_command) + + self.do_discover() + self.do_provision() + + self.debug("----- READY ---- ") + self.set_ready() +
+
[docs] def do_start(self): + if self.state == ResourceState.READY: + command = self.get("command") + self.info("Starting command '%s'" % command) + + # Vroute started during deployment + self.set_started() + else: + msg = " Failed to execute command '%s'" % command + self.error(msg, out, err) + raise RuntimeError, msg +
+
[docs] def do_stop(self): + + command = self.get('command') or '' + + if self.state == ResourceState.STARTED: + self.info("Stopping command '%s'" % self._stop_command) + + command = "bash %s" % os.path.join(self.app_home, "stop.sh") + (out, err), proc = self.execute_command(command, + blocking = True) + + self.set_stopped() +
+
[docs] def do_release(self): + # Node needs to wait until all associated RMs are released + # to be released + if not self.get("tearDown"): + self.set("tearDown", self._tear_down_command()) + + super(PlanetlabVroute, self).do_release() +
+ def _tear_down_command(self): + if self.get("action") == "del": + return + + return self._stop_command + + @property + def _start_command(self): + command = ["sudo -S python ${SRC}/pl-vroute.py"] + command.append("-a %s" % self.get("action")) + command.append("-n %s" % self.get("network")) + command.append("-p %s" % self.get("prefix")) + command.append("-g %s" % self.tap.get("pointopoint")) + command.append("-f %s" % self.tap.get("deviceName")) + command = " ".join(command) + + command = self.replace_paths(command) + return command + + @property + def _stop_command(self): + command = ["sudo -S python ${SRC}/pl-vroute.py"] + command.append("-a %s" % "del") + command.append("-n %s" % self.get("network")) + command.append("-p %s" % self.get("prefix")) + command.append("-g %s" % self.get("nexthop")) + command.append("-f %s" % self.tap.get("deviceName")) + command = " ".join(command) + + command = self.replace_paths(command) + return command + +
[docs] def valid_connection(self, guid): + # TODO: Validate! + return True +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/environ.html b/doc/sphinx/_build/html/_modules/nepi/util/environ.html new file mode 100644 index 00000000..1544b5a7 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/environ.html @@ -0,0 +1,293 @@ + + + + + + + + nepi.util.environ — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.environ

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Martin Ferrari <martin.ferrari@inria.fr>
+
+
+
+import ctypes
+import imp
+import sys
+
+import os, os.path, re, signal, shutil, socket, subprocess, tempfile
+
+__all__ =  ["python", "ssh_path"]
+__all__ += ["rsh", "tcpdump_path", "sshd_path"]
+__all__ += ["execute", "backticks"]
+
+
+# Unittest from Python 2.6 doesn't have these decorators
+def _bannerwrap(f, text):
+    name = f.__name__
+    def banner(*args, **kwargs):
+        sys.stderr.write("*** WARNING: Skipping test %s: `%s'\n" %
+                (name, text))
+        return None
+    return banner
+
+def skip(text):
+    return lambda f: _bannerwrap(f, text)
+
+def skipUnless(cond, text):
+    return (lambda f: _bannerwrap(f, text)) if not cond else lambda f: f
+
+def skipIf(cond, text):
+    return (lambda f: _bannerwrap(f, text)) if cond else lambda f: f
+
+def find_bin(name, extra_path = None):
+    search = []
+    if "PATH" in os.environ:
+        search += os.environ["PATH"].split(":")
+    for pref in ("/", "/usr/", "/usr/local/"):
+        for d in ("bin", "sbin"):
+            search.append(pref + d)
+    if extra_path:
+        search += extra_path
+
+    for d in search:
+            try:
+                os.stat(d + "/" + name)
+                return d + "/" + name
+            except OSError, e:
+                if e.errno != os.errno.ENOENT:
+                    raise
+    return None
+
+def find_bin_or_die(name, extra_path = None):
+    r = find_bin(name)
+    if not r:
+        raise RuntimeError(("Cannot find `%s' command, impossible to " +
+                "continue.") % name)
+    return r
+
+def find_bin(name, extra_path = None):
+    search = []
+    if "PATH" in os.environ:
+        search += os.environ["PATH"].split(":")
+    for pref in ("/", "/usr/", "/usr/local/"):
+        for d in ("bin", "sbin"):
+            search.append(pref + d)
+    if extra_path:
+        search += extra_path
+
+    for d in search:
+            try:
+                os.stat(d + "/" + name)
+                return d + "/" + name
+            except OSError, e:
+                if e.errno != os.errno.ENOENT:
+                    raise
+    return None
+
+ssh_path = find_bin_or_die("ssh")
+python_path = find_bin_or_die("python")
+
+# Optional tools
+rsh_path = find_bin("rsh")
+tcpdump_path = find_bin("tcpdump")
+sshd_path = find_bin("sshd")
+
+
[docs]def execute(cmd): + # FIXME: create a global debug variable + #print "[pid %d]" % os.getpid(), " ".join(cmd) + null = open("/dev/null", "r+") + p = subprocess.Popen(cmd, stdout = null, stderr = subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err)) +
+
[docs]def backticks(cmd): + p = subprocess.Popen(cmd, stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err)) + return out + + +# SSH stuff +
+def gen_ssh_keypair(filename): + ssh_keygen = nepi.util.environ.find_bin_or_die("ssh-keygen") + args = [ssh_keygen, '-q', '-N', '', '-f', filename] + assert subprocess.Popen(args).wait() == 0 + return filename, "%s.pub" % filename + +def add_key_to_agent(filename): + ssh_add = nepi.util.environ.find_bin_or_die("ssh-add") + args = [ssh_add, filename] + null = file("/dev/null", "w") + assert subprocess.Popen(args, stderr = null).wait() == 0 + null.close() + +def get_free_port(): + s = socket.socket() + s.bind(("127.0.0.1", 0)) + port = s.getsockname()[1] + return port + +_SSH_CONF = """ListenAddress 127.0.0.1:%d +Protocol 2 +HostKey %s +UsePrivilegeSeparation no +PubkeyAuthentication yes +PasswordAuthentication no +AuthorizedKeysFile %s +UsePAM no +AllowAgentForwarding yes +PermitRootLogin yes +StrictModes no +PermitUserEnvironment yes +""" + +def gen_sshd_config(filename, port, server_key, auth_keys): + conf = open(filename, "w") + text = _SSH_CONF % (port, server_key, auth_keys) + conf.write(text) + conf.close() + return filename + +def gen_auth_keys(pubkey, output, environ): + #opts = ['from="127.0.0.1/32"'] # fails in stupid yans setup + opts = [] + for k, v in environ.items(): + opts.append('environment="%s=%s"' % (k, v)) + + lines = file(pubkey).readlines() + pubkey = lines[0].split()[0:2] + out = file(output, "w") + out.write("%s %s %s\n" % (",".join(opts), pubkey[0], pubkey[1])) + out.close() + return output + +def start_ssh_agent(): + ssh_agent = nepi.util.environ.find_bin_or_die("ssh-agent") + proc = subprocess.Popen([ssh_agent], stdout = subprocess.PIPE) + (out, foo) = proc.communicate() + assert proc.returncode == 0 + d = {} + for l in out.split("\n"): + match = re.search("^(\w+)=([^ ;]+);.*", l) + if not match: + continue + k, v = match.groups() + os.environ[k] = v + d[k] = v + return d + +def stop_ssh_agent(data): + # No need to gather the pid, ssh-agent knows how to kill itself; after we + # had set up the environment + ssh_agent = nepi.util.environ.find_bin_or_die("ssh-agent") + null = file("/dev/null", "w") + proc = subprocess.Popen([ssh_agent, "-k"], stdout = null) + null.close() + assert proc.wait() == 0 + for k in data: + del os.environ[k] +
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/execfuncs.html b/doc/sphinx/_build/html/_modules/nepi/util/execfuncs.html new file mode 100644 index 00000000..7cfccc92 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/execfuncs.html @@ -0,0 +1,356 @@ + + + + + + + + nepi.util.execfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.execfuncs

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.util.sshfuncs import ProcStatus, STDOUT, log, shell_escape
+
+import logging
+import shlex
+import subprocess
+
+
[docs]def lexec(command, + user = None, + sudo = False, + env = None): + """ + Executes a local command, returns ((stdout,stderr),process) + """ + if env: + export = '' + for envkey, envval in env.iteritems(): + export += '%s=%s ' % (envkey, envval) + command = "%s %s" % (export, command) + + if sudo: + command = "sudo %s" % 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 + + 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) +
+
[docs]def lcopy(source, dest, recursive = False): + """ + Copies from/to localy. + """ + + args = ["cp"] + if recursive: + 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 = "" + 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) +
+
[docs]def lspawn(command, pidfile, + stdout = '/dev/null', + stderr = STDOUT, + stdin = '/dev/null', + home = None, + create_home = False, + sudo = False, + user = None): + """ + Spawn a local command such that it will continue working asynchronously. + + Parameters: + command: the command to run - it should be a single line. + + pidfile: path of a (ideally unique to this task) pidfile for tracking the process. + + stdout: path of a file to redirect standard output to - must be a string. + Defaults to /dev/null + stderr: path of a file to redirect standard error to - string or the special STDOUT value + to redirect to the same file stdout was redirected to. Defaults to STDOUT. + stdin: path of a file with input to be piped into the command's standard input + + home: path of a folder to use as working directory - should exist, unless you specify create_home + + create_home: if True, the home folder will be created first with mkdir -p + + sudo: whether the command needs to be executed as root + + Returns: + (stdout, stderr), process + + Of the spawning process, which only captures errors at spawning time. + Usually only useful for diagnostics. + """ + # Start process in a "daemonized" way, using nohup and heavy + # stdin/out redirection to avoid connection issues + if stderr is STDOUT: + stderr = '&1' + else: + stderr = ' ' + stderr + + daemon_command = '{ { %(command)s > %(stdout)s 2>%(stderr)s < %(stdin)s & } ; echo $! 1 > %(pidfile)s ; }' % { + 'command' : command, + 'pidfile' : shell_escape(pidfile), + 'stdout' : stdout, + 'stderr' : stderr, + 'stdin' : stdin, + } + + 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), + 'gohome' : 'cd %s ; ' % (shell_escape(home),) if home else '', + 'create' : 'mkdir -p %s ; ' % (shell_escape(home),) if create_home else '', + } + + (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) +
+
[docs]def lgetpid(pidfile): + """ + Check the pidfile of a process spawned with remote_spawn. + + Parameters: + pidfile: the pidfile passed to remote_span + + Returns: + + A (pid, ppid) tuple useful for calling remote_status and remote_kill, + or None if the pidfile isn't valid yet (maybe the process is still starting). + """ + + (out,err), proc = lexec("cat %s" % pidfile ) + + if proc.wait(): + return None + + if out: + try: + return map(int,out.strip().split(' ',1)) + except: + # Ignore, many ways to fail that don't matter that much + return None +
+
[docs]def lstatus(pid, ppid): + """ + Check the status of a process spawned with remote_spawn. + + Parameters: + pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid + + Returns: + + One of NOT_STARTED, RUNNING, FINISHED + """ + + (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, + 'pid' : pid, + }) + + if proc.wait(): + return ProcStatus.NOT_STARTED + + status = False + if out: + status = (out.strip() == 'wait') + else: + return ProcStatus.NOT_STARTED + + return ProcStatus.RUNNING if status else ProcStatus.FINISHED +
+
[docs]def lkill(pid, ppid, sudo = False): + """ + Kill a process spawned with lspawn. + + First tries a SIGTERM, and if the process does not end in 10 seconds, + it sends a SIGKILL. + + Parameters: + pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid + + sudo: whether the command was run with sudo - careful killing like this. + + Returns: + + Nothing, should have killed the process + """ + + subkill = "$(ps --ppid %(pid)d -o pid h)" % { 'pid' : pid } + cmd = """ +SUBKILL="%(subkill)s" ; +%(sudo)s kill -- -%(pid)d $SUBKILL || /bin/true +%(sudo)s kill %(pid)d $SUBKILL || /bin/true +for x in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do + sleep 0.2 + if [ `ps --pid %(pid)d -o pid | grep -c %(pid)d` == '0' ]; then + break + else + %(sudo)s kill -- -%(pid)d $SUBKILL || /bin/true + %(sudo)s kill %(pid)d $SUBKILL || /bin/true + fi + sleep 1.8 +done +if [ `ps --pid %(pid)d -o pid | grep -c %(pid)d` != '0' ]; then + %(sudo)s kill -9 -- -%(pid)d $SUBKILL || /bin/true + %(sudo)s kill -9 %(pid)d $SUBKILL || /bin/true +fi +""" + if nowait: + cmd = "( %s ) >/dev/null 2>/dev/null </dev/null &" % (cmd,) + + (out,err),proc = lexec( + cmd % { + 'ppid' : ppid, + 'pid' : pid, + 'sudo' : 'sudo -S' if sudo else '', + 'subkill' : subkill, + }) + +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/guid.html b/doc/sphinx/_build/html/_modules/nepi/util/guid.html new file mode 100644 index 00000000..3c9b96d6 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/guid.html @@ -0,0 +1,123 @@ + + + + + + + + nepi.util.guid — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.guid

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+# FIXME: This class is not thread-safe. 
+# Should it be made thread-safe?
+
[docs]class GuidGenerator(object): + def __init__(self): + self._last_guid = 0 + +
[docs] def next(self, guid = None): + if guid == None: + guid = self._last_guid + 1 + + self._last_guid = self._last_guid if guid <= self._last_guid else guid + + return guid +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/logger.html b/doc/sphinx/_build/html/_modules/nepi/util/logger.html new file mode 100644 index 00000000..ebcb7ba1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/logger.html @@ -0,0 +1,145 @@ + + + + + + + + nepi.util.logger — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.logger

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 logging
+
+
[docs]class Logger(object): + def __init__(self, logger_component): + self._logger = logging.getLogger(logger_component) + +
[docs] def debug(self, msg, out = None, err = None): + self.log(msg, logging.DEBUG, out, err) +
+
[docs] def error(self, msg, out = None, err = None): + self.log(msg, logging.ERROR, out, err) +
+
[docs] def warning(self, msg, out = None, err = None): + self.log(msg, logging.WARNING, out, err) +
+
[docs] def info(self, msg, out = None, err = None): + self.log(msg, logging.INFO, out, err) +
+
[docs] def log(self, msg, level, out = None, err = None): + if out: + msg += " - OUT: %s " % out + + if err: + msg += " - ERROR: %s " % err + + msg = self.log_message(msg) + + self.logger.log(level, msg) +
+
[docs] def log_message(self, msg): + return msg +
+ @property +
[docs] def logger(self): + return self._logger
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/manifoldapi.html b/doc/sphinx/_build/html/_modules/nepi/util/manifoldapi.html new file mode 100644 index 00000000..51245ad1 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/manifoldapi.html @@ -0,0 +1,361 @@ + + + + + + + + nepi.util.manifoldapi — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.manifoldapi

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 xmlrpclib
+import hashlib
+import threading
+
+
+
[docs]class MANIFOLDAPI(object): + """ + API to query different data platforms as SFA, TopHat, OML Central Server, + using Manifold Framework, the backend of MySlice. + """ + def __init__(self, username, password, hostname, urlpattern): + + self.auth_pwd = dict(AuthMethod='password', Username=username, + AuthString=password) + self._url = urlpattern % {'hostname':hostname} + self.lock = threading.Lock() + self.auth = self.get_session_key() + + @property +
[docs] def api(self): + return xmlrpclib.Server(self._url, allow_none = True) +
+
[docs] def get_session_key(self): + """ + Retrieves the session key, in order to use the same session for + queries. + """ + query = {'timestamp' : 'now', 'object': 'local:session', + 'filters' : [], 'fields' : [], 'action' : 'create'} + + session = self.api.forward(self.auth_pwd, query) + + if not session['value']: + msg = "Can not authenticate in Manifold API" + raise RuntimeError, msg + + session_key = session['value'][0]['session'] + return dict(AuthMethod='session', session=session_key) +
+
[docs] def get_resource_info(self, filters=None, fields=None): + """ + Create and execute the Manifold API Query to get the resources + according fields and filters. + :param filters: resource's constraints for the experiment + :type filters: dict + :param fields: desire fields in the result of the query + :type fields: list + """ + query = {'action' : 'get', 'object' : 'resource'} + + if filters: + filters = self._map_attr_to_resource_filters(filters) + + qfilters = list() + for filtername, filtervalue in filters.iteritems(): + newfilter = [filtername, "==", filtervalue] + qfilters.append(newfilter) + + query['filters'] = qfilters + + if fields: + fields = self._check_valid_fields(fields) + + if fields: + query['fields'] = fields + + return self.api.forward(self.auth, query)['value'] +
+
[docs] def get_resource_urn(self, filters=None): + """ + Retrieves the resources urn of the resources matching filters. + """ + return self.get_resource_info(filters, 'urn') +
+
[docs] def get_slice_resources(self, slicename): + """ + Retrieves resources attached to user's slice. + return value: list of resources' urn + """ + result = [] + query = {'action' : 'get', 'object' : 'resource', + 'filters' : [['slice','==', slicename]], + 'fields' : ['urn']} + + with self.lock: + value = self.api.forward(self.auth, query)['value'] + + for resource in value: + result.append(resource['urn']) + + return result +
+
[docs] def add_resource_to_slice(self, slicename, resource_urn): + """ + Add resource to user's slice. The query needs to specify the new + resource plus the previous resources already in the slice. + """ + resources = self.get_slice_resources(slicename) + resources.append(resource_urn) + + urn_list = list() + for r in resources: + urn_dict = dict() + urn_dict['urn'] = r + urn_list.append(urn_dict) + + query = {'action' : 'update', 'object' : 'slice', + 'filters' : [['slice_hrn','==', slicename]], + 'params' : {'resource' : urn_list}} + + with self.lock: + self.api.forward(self.auth, query) + + resources = self.get_slice_resources(slicename) + if resource_urn in resources: + return True + else: + msg = "Failed while trying to add %s to slice" % resource_urn + print msg + # check how to do warning + return False +
+
[docs] def remove_resource_from_slice(self, slicename, resource_urn): + """ + Remove resource from user's slice. The query needs to specify the list + of previous resources in the slice without the one to be remove. + """ + resources = self.get_slice_resources(slicename) + resources.remove(resource_urn) + + urn_list = list() + for r in resources: + urn_dict = dict() + urn_dict['urn'] = r + urn_list.append(urn_dict) + + query = {'action' : 'update', 'object' : 'slice', + 'filters' : [['slice_hrn','==', slicename]], + 'params' : {'resource' : urn_list}} + + with self.lock: + self.api.forward(self.auth, query) + + resources = self.get_slice_resources(slicename) + if resource_urn not in resources: + return True + else: + msg = "Failed while trying to remove %s to slice" % resource_urn + # check how to do warning + return False +
+ def _get_metadata(self): + """ + This method is useful to retrive metadata from different platforms + in order to update fields and possible filters. + """ + query = {'action' : 'get', 'object' : 'local:object', + 'filters' : [['table','=','resource']]} + + res = self.api.forward(self.auth, query) + + valid_fields = list() + for i in res['value'][0]['column']: + valid_fields.append(i['name']) + + return valid_fields + + def _map_attr_to_resource_filters(self, filters): + """ + Depending on the object used for the Manifold query, the filters and + fields can change its sintaxis. A resource field in a slice object + query adds 'resource.' to the field. Other changes don't follow any + particular convention. + """ + #TODO: find out useful filters + attr_to_filter = { + 'hostname' : 'hostname', + 'longitude' : 'longitude', + 'latitude' : 'latitude', + 'network' : 'network', + 'component_id' : 'component_id' + } + + mapped_filters = dict() + for filtername, filtervalue in filters.iteritems(): + if attr_to_filter[filtername]: + new_filtername = attr_to_filter[filtername] + mapped_filters[new_filtername] = filtervalue + + return mapped_filters + + def _check_valid_fields(self, fields): + """ + The fields can be a predefine set, define in the Manifold metadata. + """ + valid_fields = self._get_metadata() + + if not isinstance(fields, list): + fields = [fields] + + for field in fields: + if field not in valid_fields: + fields.remove(field) + #self.warning(" Invalid Manifold field or filter ") + + return fields + +
+
[docs]class MANIFOLDAPIFactory(object): + """ + API Factory to manage a map of MANIFOLDAPI instances as key-value pairs, it + instanciate a single instance per key. The key represents the same SFA, + MF (ManiFold) credentials. + """ + + _lock = threading.Lock() + _apis = dict() + + @classmethod +
[docs] def get_api(cls, username, password, + #hostname = "manifold.pl.sophia.inria.fr", + hostname ="test.myslice.info", + urlpattern = "http://%(hostname)s:7080"): + """ + :param username: Manifold user (also used for MySlice web login) + :type username: str + :param password: Manifold password (also used for MySlice web login) + :type password: str + :param hostname: Hostname of the Manifold API to query SFA, TopHat, etc + :type hostname: str + :param urlpattern: Url of the Manifold API to query SFA, TopHat, etc + :type urlpattern: str + """ + + if username and password: + key = cls.make_key(username, password) + with cls._lock: + api = cls._apis.get(key) + + if not api: + api = MANIFOLDAPI(username, password, hostname, urlpattern) + cls._apis[key] = api + + return api + + return None +
+ @classmethod +
[docs] def make_key(cls, *args): + skey = "".join(map(str, args)) + return hashlib.md5(skey).hexdigest() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/netgraph.html b/doc/sphinx/_build/html/_modules/nepi/util/netgraph.html new file mode 100644 index 00000000..c1c5ad87 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/netgraph.html @@ -0,0 +1,434 @@ + + + + + + + + nepi.util.netgraph — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.netgraph

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 ipaddr
+import networkx
+import math
+import random
+
+
[docs]class TopologyType: + LINEAR = "linear" + LADDER = "ladder" + MESH = "mesh" + TREE = "tree" + STAR = "star" + ADHOC = "adhoc" + +## TODO: +## - AQ: Add support for hypergraphs (to be able to add hyper edges to +## model CSMA or wireless networks) +
+
[docs]class NetGraph(object): + """ NetGraph represents a network topology. + Network graphs are internally using the networkx library. + + """ + + def __init__(self, **kwargs): + """ A graph can be generated using a specified pattern + (LADDER, MESH, TREE, etc), or provided as an argument. + + :param topology: Undirected graph to use as internal representation + :type topology: networkx.Graph + + :param topo_type: One of TopologyType.{LINEAR,LADDER,MESH,TREE,STAR} + used to automatically generate the topology graph. + :type topo_type: TopologyType + + :param node_count: Number of nodes in the topology to be generated. + :type node_count: int + + :param branches: Number of branches (arms) for the STAR topology. + :type branches: int + + + :param assign_ips: Automatically assign IP addresses to each node. + :type assign_ips: bool + + :param network: Base network segment for IP address assignment. + :type network: str + + :param prefix: Base network prefix for IP address assignment. + :type prefix: int + + :param version: IP version for IP address assignment. + :type version: int + + :param assign_st: Select source and target nodes on the graph. + :type assign_st: bool + + :param sources_targets: dictionary with the list of sources (key = + "sources") and list of targets (key = "targets") if defined, ignore + assign_st + :type sources_targets: dictionary of lists + + :param leaf_source: if True, random sources will be selected only + from leaf nodes. + :type leaf_source: bool + + NOTE: Only point-to-point like network topologies are supported for now. + (Wireless and Ethernet networks were several nodes share the same + edge (hyperedge) can not be modeled for the moment). + + """ + self._topology = kwargs.get("topology") + self._topo_type = kwargs.get("topo_type", TopologyType.ADHOC) + + if not self.topology: + if kwargs.get("node_count"): + node_count = kwargs["node_count"] + branches = kwargs.get("branches") + + self._topology = self.generate_topology(self.topo_type, + node_count, branches = branches) + else: + self._topology = networkx.Graph() + + if kwargs.get("assign_ips"): + network = kwargs.get("network", "10.0.0.0") + prefix = kwargs.get("prefix", 8) + version = kwargs.get("version", 4) + + self.assign_p2p_ips(network = network, prefix = prefix, + version = version) + + sources_targets = kwargs.get("sources_targets") + if sources_targets: + [self.set_source(n) for n in sources_targets["sources"]] + [self.set_target(n) for n in sources_targets["targets"]] + elif kwargs.get("assign_st"): + self.select_target_zero() + self.select_random_source(is_leaf = kwargs.get("leaf_source")) + + @property +
[docs] def topology(self): + return self._topology +
+ @property +
[docs] def topo_type(self): + return self._topo_type +
+ @property +
[docs] def order(self): + return self.topology.order() +
+
[docs] def nodes(self): + return self.topology.nodes() +
+
[docs] def edges(self): + return self.topology.edges() +
+
[docs] def generate_topology(self, topo_type, node_count, branches = None): + if topo_type == TopologyType.LADDER: + total_nodes = node_count/2 + graph = networkx.ladder_graph(total_nodes) + + elif topo_type == TopologyType.LINEAR: + graph = networkx.path_graph(node_count) + + elif topo_type == TopologyType.MESH: + graph = networkx.complete_graph(node_count) + + elif topo_type == TopologyType.TREE: + h = math.log(node_count + 1)/math.log(2) - 1 + graph = networkx.balanced_tree(2, h) + + elif topo_type == TopologyType.STAR: + graph = networkx.Graph() + graph.add_node(0) + + nodesinbranch = (node_count - 1)/ BRANCHES + c = 1 + + for i in xrange(BRANCHES): + prev = 0 + for n in xrange(1, nodesinbranch + 1): + graph.add_node(c) + graph.add_edge(prev, c) + prev = c + c += 1 + + return graph +
+
[docs] def add_node(self, nid): + if nid not in self.topology: + self.topology.add_node(nid) +
+
[docs] def add_edge(self, nid1, nid2): + self.add_node(nid1) + self.add_node( nid2) + + if nid1 not in self.topology[nid2]: + self.topology.add_edge(nid2, nid1) +
+
[docs] def annotate_node_ip(self, nid, ip): + if "ips" not in self.topology.node[nid]: + self.topology.node[nid]["ips"] = list() + + self.topology.node[nid]["ips"].append(ip) +
+
[docs] def node_ip_annotations(self, nid): + return self.topology.node[nid].get("ips", []) +
+
[docs] def annotate_node(self, nid, name, value): + if not isinstance(value, str) and not isinstance(value, int) and \ + not isinstance(value, float) and not isinstance(value, bool): + raise RuntimeError, "Non-serializable annotation" + + self.topology.node[nid][name] = value +
+
[docs] def node_annotation(self, nid, name): + return self.topology.node[nid].get(name) +
+
[docs] def node_annotations(self, nid): + return self.topology.node[nid].keys() +
+
[docs] def del_node_annotation(self, nid, name): + del self.topology.node[nid][name] +
+
[docs] def annotate_edge(self, nid1, nid2, name, value): + if not isinstance(value, str) and not isinstance(value, int) and \ + not isinstance(value, float) and not isinstance(value, bool): + raise RuntimeError, "Non-serializable annotation" + + self.topology.edge[nid1][nid2][name] = value +
+
[docs] def annotate_edge_net(self, nid1, nid2, ip1, ip2, mask, network, + prefixlen): + self.topology.edge[nid1][nid2]["net"] = dict() + self.topology.edge[nid1][nid2]["net"][nid1] = ip1 + self.topology.edge[nid1][nid2]["net"][nid2] = ip2 + self.topology.edge[nid1][nid2]["net"]["mask"] = mask + self.topology.edge[nid1][nid2]["net"]["network"] = network + self.topology.edge[nid1][nid2]["net"]["prefix"] = prefixlen +
+
[docs] def edge_net_annotation(self, nid1, nid2): + return self.topology.edge[nid1][nid2].get("net", dict()) +
+
[docs] def edge_annotation(self, nid1, nid2, name): + return self.topology.edge[nid1][nid2].get(name) +
+
[docs] def edge_annotations(self, nid1, nid2): + return self.topology.edge[nid1][nid2].keys() +
+
[docs] def del_edge_annotation(self, nid1, nid2, name): + del self.topology.edge[nid1][nid2][name] +
+
[docs] def assign_p2p_ips(self, network = "10.0.0.0", prefix = 8, version = 4): + """ Assign IP addresses to each end of each edge of the network graph, + computing all the point to point subnets and addresses in the network + representation. + + :param network: Base network address used for subnetting. + :type network: str + + :param prefix: Prefix for the base network address used for subnetting. + :type prefixt: int + + :param version: IP version (either 4 or 6). + :type version: int + + """ + if networkx.number_connected_components(self.topology) > 1: + raise RuntimeError("Disconnected graph!!") + + # Assign IP addresses to host + netblock = "%s/%d" % (network, prefix) + if version == 4: + net = ipaddr.IPv4Network(netblock) + new_prefix = 30 + elif version == 6: + net = ipaddr.IPv6Network(netblock) + new_prefix = 30 + else: + raise RuntimeError, "Invalid IP version %d" % version + + ## Clear all previusly assigned IPs + for nid in self.topology.nodes(): + self.topology.node[nid]["ips"] = list() + + ## Generate and assign new IPs + sub_itr = net.iter_subnets(new_prefix = new_prefix) + + for nid1, nid2 in self.topology.edges(): + #### Compute subnets for each link + + # get a subnet of base_add with prefix /30 + subnet = sub_itr.next() + mask = subnet.netmask.exploded + network = subnet.network.exploded + prefixlen = subnet.prefixlen + + # get host addresses in that subnet + i = subnet.iterhosts() + addr1 = i.next() + addr2 = i.next() + + ip1 = addr1.exploded + ip2 = addr2.exploded + self.annotate_edge_net(nid1, nid2, ip1, ip2, mask, network, + prefixlen) + + self.annotate_node_ip(nid1, ip1) + self.annotate_node_ip(nid2, ip2) +
+
[docs] def get_p2p_info(self, nid1, nid2): + net = self.topology.edge[nid1][nid2]["net"] + return ( net[nid1], net[nid2], net["mask"], net["network"], + net["prefixlen"] ) +
+
[docs] def set_source(self, nid): + self.topology.node[nid]["source"] = True +
+
[docs] def is_source(self, nid): + return self.topology.node[nid].get("source") +
+
[docs] def set_target(self, nid): + self.topology.node[nid]["target"] = True +
+
[docs] def is_target(self, nid): + return self.topology.node[nid].get("target") +
+
[docs] def targets(self): + """ Returns the nodes that are targets """ + return [nid for nid in self.topology.nodes() \ + if self.topology.node[nid].get("target")] +
+
[docs] def sources(self): + """ Returns the nodes that are sources """ + return [nid for nid in self.topology.nodes() \ + if self.topology.node[nid].get("source")] +
+
[docs] def select_target_zero(self): + """ Mark the node 0 as target + """ + nid = 0 if 0 in self.topology.nodes() else "0" + self.set_target(nid) +
+
[docs] def select_random_source(self, **kwargs): + """ Mark a random node as source. + """ + + # The ladder is a special case because is not symmetric. + if self.topo_type == TopologyType.LADDER: + total_nodes = self.order/2 + leaf1 = total_nodes + leaf2 = total_nodes - 1 + leaves = [leaf1, leaf2] + source = leaves.pop(random.randint(0, len(leaves) - 1)) + else: + # options must not be already sources or targets + options = [ k for k,v in self.topology.degree().iteritems() \ + if (not kwargs.get("is_leaf") or v == 1) \ + and not self.topology.node[k].get("source") \ + and not self.topology.node[k].get("target")] + source = options.pop(random.randint(0, len(options) - 1)) + + self.set_source(source) +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/parallel.html b/doc/sphinx/_build/html/_modules/nepi/util/parallel.html new file mode 100644 index 00000000..24b06927 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/parallel.html @@ -0,0 +1,255 @@ + + + + + + + + nepi.util.parallel — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.parallel

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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: Claudio Freire <claudio-daniel.freire@inria.fr>
+#         Alina Quereilhac <alina.quereilhac@inria.fr>
+#
+
+import threading
+import Queue
+import traceback
+import sys
+import os
+
+N_PROCS = None
+
+
[docs]class WorkerThread(threading.Thread): +
[docs] class QUIT: + pass +
+
[docs] def run(self): + while True: + task = self.queue.get() + + if task is self.QUIT: + self.queue.task_done() + break + + try: + try: + callable, args, kwargs = task + rv = callable(*args, **kwargs) + + if self.rvqueue is not None: + self.rvqueue.put(rv) + finally: + self.queue.task_done() + except: + traceback.print_exc(file = sys.stderr) + self.delayed_exceptions.append(sys.exc_info()) +
+
[docs] def attach(self, queue, rvqueue, delayed_exceptions): + self.queue = queue + self.rvqueue = rvqueue + self.delayed_exceptions = delayed_exceptions +
+
[docs] def quit(self): + self.queue.put(self.QUIT) +
+
[docs]class ParallelRun(object): + def __init__(self, maxthreads = None, maxqueue = None, results = True): + self.maxqueue = maxqueue + self.maxthreads = maxthreads + + self.queue = Queue.Queue(self.maxqueue or 0) + + self.delayed_exceptions = [] + + if results: + self.rvqueue = Queue.Queue() + else: + self.rvqueue = None + + self.initialize_workers() + +
[docs] def initialize_workers(self): + global N_PROCS + + maxthreads = self.maxthreads + + # Compute maximum number of threads allowed by the system + if maxthreads is None: + if N_PROCS is None: + try: + f = open("/proc/cpuinfo") + try: + N_PROCS = sum("processor" in l for l in f) + finally: + f.close() + except: + pass + maxthreads = N_PROCS + + if maxthreads is None: + maxthreads = 4 + + self.workers = [] + + # initialize workers + for x in xrange(maxthreads): + worker = WorkerThread() + worker.attach(self.queue, self.rvqueue, self.delayed_exceptions) + worker.setDaemon(True) + + self.workers.append(worker) +
+ def __del__(self): + self.destroy() + +
[docs] def empty(self): + while True: + try: + self.queue.get(block = False) + self.queue.task_done() + except Queue.Empty: + break +
+
[docs] def destroy(self): + self.join() + + del self.workers[:] +
+
[docs] def put(self, callable, *args, **kwargs): + self.queue.put((callable, args, kwargs)) +
+
[docs] def put_nowait(self, callable, *args, **kwargs): + self.queue.put_nowait((callable, args, kwargs)) +
+
[docs] def start(self): + for worker in self.workers: + if not worker.isAlive(): + worker.start() +
+
[docs] def join(self): + # Wait until all queued tasks have been processed + self.queue.join() + + for worker in self.workers: + worker.quit() + + for worker in self.workers: + worker.join() +
+
[docs] def sync(self): + if self.delayed_exceptions: + typ,val,loc = self.delayed_exceptions[0] + del self.delayed_exceptions[:] + raise typ,val,loc +
+ def __iter__(self): + if self.rvqueue is not None: + while True: + try: + yield self.rvqueue.get_nowait() + except Queue.Empty: + self.queue.join() + try: + yield self.rvqueue.get_nowait() + except Queue.Empty: + raise StopIteration +
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/parsers/xml_parser.html b/doc/sphinx/_build/html/_modules/nepi/util/parsers/xml_parser.html new file mode 100644 index 00000000..1d92a071 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/parsers/xml_parser.html @@ -0,0 +1,549 @@ + + + + + + + + nepi.util.parsers.xml_parser — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.parsers.xml_parser

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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.util.netgraph import NetGraph, TopologyType 
+from nepi.util.timefuncs import stformat, tsformat
+
+from xml.dom import minidom
+
+import datetime
+import sys
+import os
+
+STRING = "string"
+BOOL = "bool"
+INTEGER = "integer"
+DOUBLE = "float"
+
+
[docs]def xmlencode(s): + if isinstance(s, str): + rv = s.decode("latin1") + if isinstance(s, datetime.datetime): + rv = tsformat(s) + elif not isinstance(s, unicode): + rv = unicode(s) + else: + rv = s + return rv.replace(u'\x00',u'&#0000;') +
+
[docs]def xmldecode(s, cast = str): + ret = s.replace(u'&#0000',u'\x00').encode("ascii") + ret = cast(ret) + if s == "None": + return None + return ret +
+
[docs]def from_type(value): + if isinstance(value, bool): + return BOOL + if isinstance(value, int): + return INTEGER + if isinstance(value, float): + return DOUBLE + + return STRING +
+
[docs]def to_type(type, value): + if not value: + return value + + if type == STRING: + return str(value) + if type == BOOL: + return value == "True" + if type == INTEGER: + return int(value) + if type == DOUBLE: + return float(value) +
+
[docs]class ECXMLParser(object): +
[docs] def to_xml(self, ec): + + doc = minidom.Document() + + self._ec_to_xml(doc, ec) + + try: + xml = doc.toprettyxml(indent=" ", encoding="UTF-8") + except: + print >>sys.stderr, "Oops: generating XML from %s" % (data,) + raise + + return xml +
+ def _ec_to_xml(self, doc, ec): + ecnode = doc.createElement("experiment") + ecnode.setAttribute("exp_id", xmlencode(ec.exp_id)) + ecnode.setAttribute("run_id", xmlencode(ec.run_id)) + ecnode.setAttribute("nthreads", xmlencode(ec.nthreads)) + ecnode.setAttribute("local_dir", xmlencode(ec.local_dir)) + doc.appendChild(ecnode) + + if ec.netgraph != None: + self._netgraph_to_xml(doc, ecnode, ec) + + rmsnode = doc.createElement("rms") + ecnode.appendChild(rmsnode) + + for guid, rm in ec._resources.iteritems(): + self._rm_to_xml(doc, rmsnode, ec, guid, rm) + + return doc + + def _netgraph_to_xml(self, doc, ecnode, ec): + ngnode = doc.createElement("topology") + ngnode.setAttribute("topo-type", xmlencode(ec.netgraph.topo_type)) + ecnode.appendChild(ngnode) + + self. _netgraph_nodes_to_xml(doc, ngnode, ec) + self. _netgraph_edges_to_xml(doc, ngnode, ec) + + def _netgraph_nodes_to_xml(self, doc, ngnode, ec): + ngnsnode = doc.createElement("nodes") + ngnode.appendChild(ngnsnode) + + for nid in ec.netgraph.nodes(): + ngnnode = doc.createElement("node") + ngnnode.setAttribute("nid", xmlencode(nid)) + ngnnode.setAttribute("nid-type", from_type(nid)) + ngnsnode.appendChild(ngnnode) + + # Mark ources and targets + if ec.netgraph.is_source(nid): + ngnnode.setAttribute("source", xmlencode(True)) + + if ec.netgraph.is_target(nid): + ngnnode.setAttribute("target", xmlencode(True)) + + # Node annotations + annosnode = doc.createElement("node-annotations") + add_annotations = False + for name in ec.netgraph.node_annotations(nid): + add_annotations = True + value = ec.netgraph.node_annotation(nid, name) + annonode = doc.createElement("node-annotation") + annonode.setAttribute("name", xmlencode(name)) + annonode.setAttribute("value", xmlencode(value)) + annonode.setAttribute("type", from_type(value)) + annosnode.appendChild(annonode) + + if add_annotations: + ngnnode.appendChild(annosnode) + + def _netgraph_edges_to_xml(self, doc, ngnode, ec): + ngesnode = doc.createElement("edges") + ngnode.appendChild(ngesnode) + + for nid1, nid2 in ec.netgraph.edges(): + ngenode = doc.createElement("edge") + ngenode.setAttribute("nid1", xmlencode(nid1)) + ngenode.setAttribute("nid1-type", from_type(nid1)) + ngenode.setAttribute("nid2", xmlencode(nid2)) + ngenode.setAttribute("nid2-type", from_type(nid2)) + ngesnode.appendChild(ngenode) + + # Edge annotations + annosnode = doc.createElement("edge-annotations") + add_annotations = False + for name in ec.netgraph.edge_annotations(nid1, nid2): + add_annotations = True + value = ec.netgraph.edge_annotation(nid1, nid2, name) + annonode = doc.createElement("edge-annotation") + annonode.setAttribute("name", xmlencode(name)) + annonode.setAttribute("value", xmlencode(value)) + annonode.setAttribute("type", from_type(value)) + annosnode.appendChild(annonode) + + if add_annotations: + ngenode.appendChild(annosnode) + + def _rm_to_xml(self, doc, rmsnode, ec, guid, rm): + rmnode = doc.createElement("rm") + rmnode.setAttribute("guid", xmlencode(guid)) + rmnode.setAttribute("rtype", xmlencode(rm._rtype)) + rmnode.setAttribute("state", xmlencode(rm._state)) + if rm._start_time: + rmnode.setAttribute("start_time", xmlencode(rm._start_time)) + if rm._stop_time: + rmnode.setAttribute("stop_time", xmlencode(rm._stop_time)) + if rm._discover_time: + rmnode.setAttribute("discover_time", xmlencode(rm._discover_time)) + if rm._provision_time: + rmnode.setAttribute("provision_time", xmlencode(rm._provision_time)) + if rm._ready_time: + rmnode.setAttribute("ready_time", xmlencode(rm._ready_time)) + if rm._release_time: + rmnode.setAttribute("release_time", xmlencode(rm._release_time)) + if rm._failed_time: + rmnode.setAttribute("failed_time", xmlencode(rm._failed_time)) + rmsnode.appendChild(rmnode) + + anode = doc.createElement("attributes") + attributes = False + + for attr in rm._attrs.values(): + if attr.has_changed: + attributes = True + aanode = doc.createElement("attribute") + aanode.setAttribute("name", xmlencode(attr.name)) + aanode.setAttribute("value", xmlencode(attr.value)) + aanode.setAttribute("type", from_type(attr.value)) + anode.appendChild(aanode) + + if attributes: + rmnode.appendChild(anode) + + cnode = doc.createElement("connections") + connections = False + + for guid in rm._connections: + connections = True + ccnode = doc.createElement("connection") + ccnode.setAttribute("guid", xmlencode(guid)) + cnode.appendChild(ccnode) + + if connections: + rmnode.appendChild(cnode) + + cnnode = doc.createElement("conditions") + conditions = False + + for action, conds in rm._conditions.iteritems(): + conditions = True + for (group, state, time) in conds: + ccnnode = doc.createElement("condition") + ccnnode.setAttribute("action", xmlencode(action)) + ccnnode.setAttribute("group", xmlencode(group)) + ccnnode.setAttribute("state", xmlencode(state)) + ccnnode.setAttribute("time", xmlencode(time)) + cnnode.appendChild(ccnnode) + + if conditions: + rmnode.appendChild(cnnode) + + tnode = doc.createElement("traces") + traces = False + + for trace in rm._trcs.values(): + if trace.enabled: + traces = True + ttnode = doc.createElement("trace") + ttnode.setAttribute("name", xmlencode(trace.name)) + tnode.appendChild(ttnode) + + if traces: + rmnode.appendChild(tnode) + +
[docs] def from_xml(self, xml): + doc = minidom.parseString(xml) + return self._ec_from_xml(doc) +
+ def _ec_from_xml(self, doc): + from nepi.execution.ec import ExperimentController + ec = None + + ecnode_list = doc.getElementsByTagName("experiment") + for ecnode in ecnode_list: + if ecnode.nodeType == doc.ELEMENT_NODE: + exp_id = xmldecode(ecnode.getAttribute("exp_id")) + run_id = xmldecode(ecnode.getAttribute("run_id")) + local_dir = xmldecode(ecnode.getAttribute("local_dir")) + + # Configure number of preocessing threads + nthreads = xmldecode(ecnode.getAttribute("nthreads")) + os.environ["NEPI_NTHREADS"] = nthreads + + # Deserialize netgraph + topology = None + topo_type = None + + netgraph = self._netgraph_from_xml(doc, ecnode) + + if netgraph: + topo_type = netgraph.topo_type + topology = netgraph.topology + + # Instantiate EC + ec = ExperimentController(exp_id = exp_id, local_dir = local_dir, + topology = topology, topo_type = topo_type) + + connections = set() + + rmsnode_list = ecnode.getElementsByTagName("rms") + if rmsnode_list: + rmnode_list = rmsnode_list[0].getElementsByTagName("rm") + for rmnode in rmnode_list: + if rmnode.nodeType == doc.ELEMENT_NODE: + self._rm_from_xml(doc, rmnode, ec, connections) + + for (guid1, guid2) in connections: + ec.register_connection(guid1, guid2) + + break + + return ec + + def _netgraph_from_xml(self, doc, ecnode): + netgraph = None + + topology = ecnode.getElementsByTagName("topology") + if topology: + topology = topology[0] + topo_type = xmldecode(topology.getAttribute("topo-type")) + + netgraph = NetGraph(topo_type = topo_type) + + ngnsnode_list = topology.getElementsByTagName("nodes") + if ngnsnode_list: + ngnsnode = ngnsnode_list[0].getElementsByTagName("node") + for ngnnode in ngnsnode: + nid = xmldecode(ngnnode.getAttribute("nid")) + tipe = xmldecode(ngnnode.getAttribute("nid-type")) + nid = to_type(tipe, nid) + netgraph.add_node(nid) + + if ngnnode.hasAttribute("source"): + netgraph.set_source(nid) + if ngnnode.hasAttribute("target"): + netgraph.set_target(nid) + + annosnode_list = ngnnode.getElementsByTagName("node-annotations") + + if annosnode_list: + annosnode = annosnode_list[0].getElementsByTagName("node-annotation") + for annonode in annosnode: + name = xmldecode(annonode.getAttribute("name")) + + if name == "ips": + ips = xmldecode(annonode.getAttribute("value"), eval) # list + for ip in ips: + netgraph.annotate_node_ip(nid, ip) + else: + value = xmldecode(annonode.getAttribute("value")) + tipe = xmldecode(annonode.getAttribute("type")) + value = to_type(tipe, value) + netgraph.annotate_node(nid, name, value) + + ngesnode_list = topology.getElementsByTagName("edges") + if ngesnode_list: + ngesnode = ngesnode_list[0].getElementsByTagName("edge") + for ngenode in ngesnode: + nid1 = xmldecode(ngenode.getAttribute("nid1")) + tipe1 = xmldecode(ngenode.getAttribute("nid1-type")) + nid1 = to_type(tipe1, nid1) + + nid2 = xmldecode(ngenode.getAttribute("nid2")) + tipe2 = xmldecode(ngenode.getAttribute("nid2-type")) + nid2 = to_type(tipe2, nid2) + + netgraph.add_edge(nid1, nid2) + + annosnode_list = ngenode.getElementsByTagName("edge-annotations") + if annosnode_list: + annosnode = annosnode_list[0].getElementsByTagName("edge-annotation") + for annonode in annosnode: + name = xmldecode(annonode.getAttribute("name")) + + if name == "net": + net = xmldecode(annonode.getAttribute("value"), eval) # dict + netgraph.annotate_edge_net(nid1, nid2, net[nid1], net[nid2], + net["mask"], net["network"], net["prefix"]) + else: + value = xmldecode(annonode.getAttribute("value")) + tipe = xmldecode(annonode.getAttribute("type")) + value = to_type(tipe, value) + netgraph.annotate_edge(nid1, nid2, name, value) + return netgraph + + def _rm_from_xml(self, doc, rmnode, ec, connections): + start_time = None + stop_time = None + discover_time = None + provision_time = None + ready_time = None + release_time = None + failed_time = None + + guid = xmldecode(rmnode.getAttribute("guid"), int) + rtype = xmldecode(rmnode.getAttribute("rtype")) + + # FOR NOW ONLY STATE NEW IS ALLOWED + state = 0 + """ + state = xmldecode(rmnode.getAttribute("state"), int) + + if rmnode.hasAttribute("start_time"): + start_time = xmldecode(rmnode.getAttribute("start_time"), + datetime.datetime) + if rmnode.hasAttribute("stop_time"): + stop_time = xmldecode(rmnode.getAttribute("stop_time"), + datetime.datetime) + if rmnode.hasAttribute("discover_time"): + dicover_time = xmldecode(rmnode.getAttribute("discover_time"), + datetime.datetime) + if rmnode.hasAttribute("provision_time"): + provision_time = xmldecode(rmnode.getAttribute("provision_time"), + datetime.datetime) + if rmnode.hasAttribute("ready_time"): + ready_time = xmldecode(rmnode.getAttribute("ready_time"), + datetime.datetime) + if rmnode.hasAttribute("release_time"): + release_time = xmldecode(rmnode.getAttribute("release_time"), + datetime.datetime) + if rmnode.hasAttribute("failed_time"): + failed_time = xmldecode(rmnode.getAttribute("failed_time"), + datetime.datetime) + """ + + ec.register_resource(rtype, guid = guid) + rm = ec.get_resource(guid) + rm.set_state_time(state, "_start_time", start_time) + rm.set_state_time(state, "_stop_time", stop_time) + rm.set_state_time(state, "_discover_time", discover_time) + rm.set_state_time(state, "_provision_time", provision_time) + rm.set_state_time(state, "_ready_time", ready_time) + rm.set_state_time(state, "_release_time", release_time) + rm.set_state_time(state, "_failed_time", failed_time) + + anode_list = rmnode.getElementsByTagName("attributes") + if anode_list: + aanode_list = anode_list[0].getElementsByTagName("attribute") + for aanode in aanode_list: + name = xmldecode(aanode.getAttribute("name")) + value = xmldecode(aanode.getAttribute("value")) + tipe = xmldecode(aanode.getAttribute("type")) + value = to_type(tipe, value) + rm.set(name, value) + + cnode_list = rmnode.getElementsByTagName("connections") + if cnode_list: + ccnode_list = cnode_list[0].getElementsByTagName("connection") + for ccnode in ccnode_list: + guid2 = xmldecode(ccnode.getAttribute("guid"), int) + connections.add((guid, guid2)) + + tnode_list = rmnode.getElementsByTagName("traces") + if tnode_list: + ttnode_list = tnode_list[0].getElementsByTagName("trace") + for ttnode in ttnode_list: + name = xmldecode(ttnode.getAttribute("name")) + ec.enable_trace(guid, name) + + cnnode_list = rmnode.getElementsByTagName("conditions") + if cnnode_list: + ccnnode_list = cnnode_list[0].getElementsByTagName("condition") + for ccnnode in ccnnode_list: + action = xmldecode(ccnnode.getAttribute("action"), int) + group = xmldecode(ccnnode.getAttribute("group"), eval) # list + state = xmldecode(ccnnode.getAttribute("state"), int) + time = xmldecode(ccnnode.getAttribute("time")) + time = to_type('STRING', time) + ec.register_condition(guid, action, group, state, time = time) +
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/plotter.html b/doc/sphinx/_build/html/_modules/nepi/util/plotter.html new file mode 100644 index 00000000..3276b3c4 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/plotter.html @@ -0,0 +1,198 @@ + + + + + + + + nepi.util.plotter — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.plotter

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 logging
+import os
+
+try:
+    import networkx
+except ImportError:
+    msg = "Networkx library is not installed, you will not be able to plot."
+    logger = logging.Logger("Plotter")
+    logger.debug(msg)
+
+try:
+    import matplotlib.pyplot as plt
+except:
+    msg = ("Matplotlib library is not installed or X11 is not enabled. "
+        "You will not be able generate PNG plots.")
+    logger = logging.Logger("Plotter")
+    logger.debug(msg)
+
+
[docs]class PFormats: + DOT = "dot" + FIGURE = "figure" +
+
[docs]class ECPlotter(object): +
[docs] def plot(self, ec, dirpath = None, format= PFormats.FIGURE, + show = False): + graph, labels = self._ec2graph(ec) + + add_extension = False + + if not dirpath: + import tempfile + dirpath = tempfile.mkdtemp() + + fpath = os.path.join(dirpath, "%s_%s" % (ec.exp_id, ec.run_id)) + + if format == PFormats.FIGURE: + pos = networkx.graphviz_layout(graph, prog="neato") + networkx.draw(graph, pos = pos, node_color="white", + node_size = 500, with_labels=True) + + label = "\n".join(map(lambda v: "%s: %s" % (v[0], v[1]), labels.iteritems())) + plt.annotate(label, xy=(0.05, 0.95), xycoords='axes fraction') + + fpath += ".png" + + plt.savefig(fpath, bbox_inches="tight") + + if show: + plt.show() + + elif format == PFormats.DOT: + fpath += ".dot" + + networkx.write_dot(graph, fpath) + + if show: + import subprocess + subprocess.call(["dot", "-Tps", fpath, "-o", "%s.ps" % fpath]) + subprocess.call(["evince","%s.ps" % fpath]) + + return fpath +
+ def _ec2graph(self, ec): + graph = networkx.Graph(graph = dict(overlap = "false")) + + labels = dict() + connections = set() + + for guid, rm in ec._resources.iteritems(): + label = rm.get_rtype() + + graph.add_node(guid, + label = "%d %s" % (guid, label), + width = 50/72.0, # 1 inch = 72 points + height = 50/72.0, + shape = "circle") + + labels[guid] = label + + for guid2 in rm.connections: + # Avoid adding a same connection twice + if (guid2, guid) not in connections: + connections.add((guid, guid2)) + + for (guid1, guid2) in connections: + graph.add_edge(guid1, guid2) + + return graph, labels
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/rmatcher.html b/doc/sphinx/_build/html/_modules/nepi/util/rmatcher.html new file mode 100644 index 00000000..3279823f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/rmatcher.html @@ -0,0 +1,155 @@ + + + + + + + + nepi.util.rmatcher — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.rmatcher

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+
+
[docs]def match_tags(box, all_tags, exact_tags): + """ returns True if box has required tags """ + tall = set(all_tags) + texact = set(exact_tags) + + if texact and box.connections == texact: + return True + + if tall and tall.issubset(box.connections): + return True + + return False +
+
[docs]def find_boxes(box, all_tags = None, exact_tags = None, max_depth = 1): + """ Look for the connected boxes with the required tags, doing breath-first + search, until max_depth ( max_depth = None will traverse the entire graph ). + """ + if not all_tags and not exact_tags: + msg = "No matching criteria for resources." + raise RuntimeError(msg) + + queue = set() + # enqueue (depth, box) + queue.add((0, box)) + + traversed = set() + traversed.add(box) + + depth = 0 + + result = set() + + while len(q) > 0: + (depth, a) = queue.pop() + if match_tags(a, all_tags, exact_tags): + result.add(a) + + if not max_depth or depth <= max_depth: + depth += 1 + for b in sorted(a.connections): + if b not in traversed: + traversed.add(b) + queue.add((depth, b)) + + return result
+
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/serializer.html b/doc/sphinx/_build/html/_modules/nepi/util/serializer.html new file mode 100644 index 00000000..9514b5ea --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/serializer.html @@ -0,0 +1,151 @@ + + + + + + + + nepi.util.serializer — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.serializer

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 datetime
+import os
+
+
[docs]class SFormats: + XML = "xml" +
+
[docs]class ECSerializer(object): +
[docs] def load(self, filepath, format = SFormats.XML): + if format == SFormats.XML: + from nepi.util.parsers.xml_parser import ECXMLParser + + parser = ECXMLParser() + f = open(filepath, "r") + xml = f.read() + f.close() + + ec = parser.from_xml(xml) + + return ec +
+
[docs] def serialize(self, ec, format = SFormats.XML): + if format == SFormats.XML: + from nepi.util.parsers.xml_parser import ECXMLParser + + parser = ECXMLParser() + sec = parser.to_xml(ec) + + return sec +
+
[docs] def save(self, ec, dirpath, format = SFormats.XML): + date = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + filename = "%s_%s" % (ec.exp_id, date) + + if format == SFormats.XML: + filepath = os.path.join(dirpath, "%s.xml" % filename) + sec = self.serialize(ec, format = format) + f = open(filepath, "w") + f.write(sec) + f.close() + + return filepath +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/sfaapi.html b/doc/sphinx/_build/html/_modules/nepi/util/sfaapi.html new file mode 100644 index 00000000..1939a77b --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/sfaapi.html @@ -0,0 +1,562 @@ + + + + + + + + nepi.util.sfaapi — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.sfaapi

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+import time
+
+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
+
+
[docs]class SFAAPI(object): + """ + API for quering the SFA service. It uses Sfi class from the tool sfi client. + """ + def __init__(self, sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, + batch, rtype, timeout): + + self._blacklist = set() + self._reserved = set() + self._resources_cache = None + self._already_cached = False + self._ec = ec + self.apis = 1 + + if batch: + self._testbed_res = rtype + self._count = 0 + self._total = self._get_total_res() + self._slice_resources_batch = list() + + 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): + """ + Initialize the blacklist with previous nodes blacklisted, in + previous runs. + """ + 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 _get_total_res(self): + """ + Get the total amount of resources instanciated using this API, + to be able to add them using the same Allocate and Provision + call at once. Specially for Wilabt testbed that doesn't allow + to add slivers after the slice already has some. + """ + rms = list() + res_gids = self._ec.resources + for gid in res_gids: + rm = self._ec.get_resource(gid) + if self._testbed_res.lower() in rm._rtype.lower(): + rms.append(rm) + return rms + + def _sfi_exec_method(self, command, slicename=None, rspec=None, urn=None, action=None): + """ + Execute sfi method, which correspond to SFA call. It can be the following + calls: Describe, Delete, Allocate, Provision, ListResources. + """ + if command in ['describe', 'delete', 'allocate', 'provision', 'action']: + 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] + else: + args_list = [slicename] + if command != 'delete': + args_list = args_list + ['-o', '/tmp/rspec_output'] + if command == 'action': + args_list = [slicename, action] + + 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) + self.api.command_options = command_options + self.api.read_config() + self.api.bootstrap() + + try: + os.remove("/tmp/rspec_output.rspec") + except OSError: + self._log.debug("Couldn't remove temporary output file for RSpec or it doesn't exist") + + try: + self.api.dispatch(command, command_options, command_args) + with open("/tmp/rspec_output.rspec", "r") as result_file: + result = result_file.read() + return result + except: + self._log.debug(" Couldn't retrive rspec output information from method %s " % command) + return None + +
[docs] 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 +
+
[docs] 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 +
+
[docs] 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: + self._log.debug("Fail to describe resources for slice %s, slice may be empty" % slicename) + + if rspec_slice is not None: + result = self.rspec_proc.parse_sfa_rspec(rspec_slice) + return result + else: + return {'resource':[],'lease':[]} + +
+
[docs] 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) + + with self.lock_slice: + rspec_slice = self._sfi_exec_method('describe', slicename) + if rspec_slice is not None: + slice_resources = self.rspec_proc.parse_sfa_rspec(rspec_slice)['resource'] + else: slice_resources = [] + 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, None, 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) + + # ALLOCATE + try: + self._log.debug("Allocating resources in slice %s" % slicename) + out = self._sfi_exec_method('allocate', slicename, "/tmp/rspec_input.rspec") + except: + raise RuntimeError("Fail to allocate resource for slice %s" % slicename) + + if out is not None: + # PROVISION + try: + self._log.debug("Provisioning resources in slice %s" % slicename) + self._sfi_exec_method('provision', slicename) + except: + raise RuntimeError("Fail to provision resource for slice %s" % slicename) + return True +
+
[docs] def add_resource_to_slice_batch(self, slicename, resource_hrn, properties=None, leases=None): + """ + Method to add all resources together to the slice. Previous deletion of slivers. + Specially used for wilabt that doesn't allow to add more resources to the slice + after some resources are added. Every sliver have to be deleted and the batch + has to be added at once. + """ + self._count += 1 + self._slice_resources_batch.append(resource_hrn) + resources_hrn_new = list() + if self._count == len(self._total): + check_all_inslice = self._check_all_inslice(self._slice_resources_batch, slicename) + if check_all_inslice == True: + return True + for resource_hrn in self._slice_resources_batch: + resource_parts = resource_hrn.split('.') + resource_hrn = '.'.join(resource_parts[:2]) + '.' + '\\.'.join(resource_parts[2:]) + resources_hrn_new.append(resource_hrn) + with self.lock_slice: + if check_all_inslice != 0: + self._sfi_exec_method('delete', slicename) + time.sleep(480) + + # Re implementing urn from hrn because the library sfa-common doesn't work for wilabt + resources_urn = self._get_urn(resources_hrn_new) + rspec = self.rspec_proc.build_sfa_rspec(slicename, resources_urn, properties, 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 resources in slice %s" % slicename) + + # ALLOCATE + try: + self._log.debug("Allocating resources in slice %s" % slicename) + out = self._sfi_exec_method('allocate', slicename, "/tmp/rspec_input.rspec") + except: + raise RuntimeError("Fail to allocate resource for slice %s" % slicename) + + if out is not None: + # PROVISION + try: + self._log.debug("Provisioning resources in slice %s" % slicename) + self._sfi_exec_method('provision', slicename) + self._sfi_exec_method('action', slicename=slicename, action='geni_start') + except: + raise RuntimeError("Fail to provision resource for slice %s" % slicename) + return True + else: + raise RuntimeError("Fail to allocate resources for slice %s" % slicename) + + else: + self._log.debug(" Waiting for more nodes to add the batch to the slice ") +
+ def _check_all_inslice(self, resources_hrn, slicename): + slice_res = self.get_slice_resources(slicename)['resource'] + if slice_res: + if len(slice_res[0]['services']) != 0: + slice_res_hrn = self.get_resources_hrn(slice_res).values() + if self._compare_lists(slice_res_hrn, resources_hrn): + return True + else: return len(slice_res_hrn) + return 0 + + def _compare_lists(self, list1, list2): + if len(list1) != len(list2): + return False + for item in list1: + if item not in list2: + return False + return True + + def _get_urn(self, resources_hrn): + """ + Get urn from hrn. + """ + resources_urn = list() + for hrn in resources_hrn: + hrn = hrn.replace("\\", "").split('.') + node = hrn.pop() + auth = '.'.join(hrn) + urn = ['urn:publicid:IDN+', auth, '+node+', node] + urn = ''.join(urn) + resources_urn.append(urn) + return resources_urn + +
[docs] def remove_resource_from_slice(self, slicename, resource_hrn, leases=None): + """ + Remove slivers from slice. Currently sfi doesn't support removing particular + slivers. + """ + resource_urn = self._get_resources_urn([resource_hrn]).pop() + with self.lock_slice: + try: + self._sfi_exec_method('delete', slicename, urn=resource_urn) + except: + raise RuntimeError("Fail to delete resource for slice %s" % slicename) + return True +
+
[docs] def remove_all_from_slice(self, slicename): + """ + De-allocate and de-provision all slivers of the named slice. + Currently sfi doesn't support removing particular + slivers, so this method works only for removing every sliver. Setting the + resource_hrn parameter is not necessary. + """ + with self.lock_slice: + try: + self._sfi_exec_method('delete', slicename) + except: + raise RuntimeError("Fail to delete slivers 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 + +
[docs] def blacklist_resource(self, resource_hrn): + """ + Adding resource_hrn to blacklist, and taking + the resource from the reserved list. + """ + with self.lock_blist: + self._blacklist.add(resource_hrn) + with self.lock_resv: + if resource_hrn in self._reserved: + self._reserved.remove(resource_hrn) +
+
[docs] def blacklisted(self, resource_hrn): + """ + Check if the resource is in the blacklist. + """ + with self.lock_blist: + if resource_hrn in self._blacklist: + return True + return False +
+
[docs] def reserve_resource(self, resource_hrn): + """ + Add resource to the reserved list. + """ + self._reserved.add(resource_hrn) +
+
[docs] def reserved(self, resource_hrn): + """ + Check that the resource in not reserved. + """ + with self.lock_resv: + if resource_hrn in self._reserved: + return True + else: + self.reserve_resource(resource_hrn) + return False +
+
[docs] def release(self): + """ + Remove hosts from the reserved and blacklist lists, and in case + the persist attribute is set, it saves the blacklisted hosts + in the blacklist file. + """ + self.apis -= 1 + if self.apis == 0: + blacklist = self._blacklist + self._blacklist = set() + self._reserved = set() +# if self._ecobj.get_global('PlanetlabSfaNode', 'persist_blacklist'): +# if blacklist: +# to_blacklist = list() +# hostnames = self.get_nodes(list(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) +# + +
+
[docs]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 +
[docs] def get_api(cls, sfi_user, sfi_auth, sfi_registry, sfi_sm, private_key, ec, + batch = False, rtype = None, 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, batch, rtype, timeout) + cls._apis[key] = api + else: + api.apis += 1 + + return api + + return None +
+ @classmethod +
[docs] def make_key(cls, *args): + skey = "".join(map(str, args)) + return hashlib.md5(skey).hexdigest() +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/sfarspec_proc.html b/doc/sphinx/_build/html/_modules/nepi/util/sfarspec_proc.html new file mode 100644 index 00000000..9561359f --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/sfarspec_proc.html @@ -0,0 +1,312 @@ + + + + + + + + nepi.util.sfarspec_proc — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.sfarspec_proc

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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
+
+
+
[docs]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 + +
[docs] 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 +
+
[docs] 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 \ +# } + +
+
[docs] def build_sfa_rspec(self, slice_id, resources, properties, 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.debug("Building RSpec for resources %s" % resources) + cardinal = 0 + wilab = False + for urn in resources: + # XXX TO BE CORRECTED, this handles None values + if not urn: + continue + self._log.debug(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 !!! +# Commented Lucia, doesn't work for wilabt +# if self.config: +# if 'wilab2' in self.config['sm']: +# resource['client_id'] = "PC" +# resource['sliver_type'] = "raw-pc" + if 'wilab2' in urn: + wilab = True + resource['client_id'] = "node%s" % cardinal + resource['sliver_type'] = "raw-pc" + resource['disk_image'] = "hola" + top_auth = resource_hrn.replace("\\", "").split('.') + top_auth.pop() + top_auth = '.'.join(top_auth) + cm = urn.split("+") + resource['component_manager_id'] = "%s+%s+authority+cm" % (cm[0],top_auth) + cardinal += 1 + 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.debug("request rspec: %s"%rspec.toxml()) + string = rspec.toxml() + if wilab and properties is not None: + ## dirty hack for the f4f demo + b = string.split('\n') + for i, n in enumerate(b): + if 'sliver_type name="raw-pc"' in n: + b[i] = '<sliver_type name="raw-pc">' + b.insert(i+1, '<disk_image name="urn:publicid:IDN+wall2.ilabt.iminds.be+image+emulab-ops//%s"/>' % properties['disk_image']) + #b.insert(i+1, '<disk_image name="urn:publicid:IDN+wilab2.ilabt.iminds.be+image+nepi:%s"/>' % properties['disk_image']) + b.insert(i+2, '</sliver_type>') + string = ''.join(b) + self._log.debug("request rspec : %s" % string) + return string +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/sshfuncs.html b/doc/sphinx/_build/html/_modules/nepi/util/sshfuncs.html new file mode 100644 index 00000000..b588babb --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/sshfuncs.html @@ -0,0 +1,988 @@ + + + + + + + + nepi.util.sshfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.sshfuncs

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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>
+#         Claudio Freire <claudio-daniel.freire@inria.fr>
+
+## TODO: This code needs reviewing !!!
+
+import base64
+import errno
+import hashlib
+import logging
+import os
+import os.path
+import re
+import select
+import signal
+import socket
+import subprocess
+import threading
+import time
+import tempfile
+
+_re_inet = re.compile("\d+:\s+(?P<name>[a-z0-9_-]+)\s+inet6?\s+(?P<inet>[a-f0-9.:/]+)\s+(brd\s+[0-9.]+)?.*scope\s+global.*") 
+
+logger = logging.getLogger("sshfuncs")
+
+
[docs]def log(msg, level, out = None, err = None): + if out: + msg += " - OUT: %s " % out + + if err: + msg += " - ERROR: %s " % err + + logger.log(level, msg) +
+if hasattr(os, "devnull"): + DEV_NULL = os.devnull +else: + DEV_NULL = "/dev/null" + +SHELL_SAFE = re.compile('^[-a-zA-Z0-9_=+:.,/]*$') + +
[docs]class STDOUT: + """ + Special value that when given to rspawn in stderr causes stderr to + redirect to whatever stdout was redirected to. + """ +
+
[docs]class ProcStatus: + """ + Codes for status of remote spawned process + """ + # Process is still running + RUNNING = 1 + + # Process is finished + FINISHED = 2 + + # Process hasn't started running yet (this should be very rare) + NOT_STARTED = 3 +
+hostbyname_cache = dict() +hostbyname_cache_lock = threading.Lock() + +
[docs]def resolve_hostname(host): + ip = None + + if host in ["localhost", "127.0.0.1", "::1"]: + p = subprocess.Popen("ip -o addr list", shell=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + m = _re_inet.findall(stdout) + ip = m[0][1].split("/")[0] + else: + ip = socket.gethostbyname(host) + + return ip +
+
[docs]def gethostbyname(host): + global hostbyname_cache + global hostbyname_cache_lock + + hostbyname = hostbyname_cache.get(host) + if not hostbyname: + with hostbyname_cache_lock: + hostbyname = resolve_hostname(host) + hostbyname_cache[host] = hostbyname + + msg = " Added hostbyname %s - %s " % (host, hostbyname) + log(msg, logging.DEBUG) + + return hostbyname +
+OPENSSH_HAS_PERSIST = None + +
[docs]def openssh_has_persist(): + """ The ssh_config options ControlMaster and ControlPersist allow to + reuse a same network connection for multiple ssh sessions. In this + way limitations on number of open ssh connections can be bypassed. + However, older versions of openSSH do not support this feature. + This function is used to determine if ssh connection persist features + can be used. + """ + global OPENSSH_HAS_PERSIST + if OPENSSH_HAS_PERSIST is None: + proc = subprocess.Popen(["ssh","-v"], + stdout = subprocess.PIPE, + stderr = subprocess.STDOUT, + stdin = open("/dev/null","r") ) + out,err = proc.communicate() + proc.wait() + + vre = re.compile(r'OpenSSH_(?:[6-9]|5[.][8-9]|5[.][1-9][0-9]|[1-9][0-9]).*', re.I) + OPENSSH_HAS_PERSIST = bool(vre.match(out)) + return OPENSSH_HAS_PERSIST +
+
[docs]def make_server_key_args(server_key, host, port): + """ Returns a reference to a temporary known_hosts file, to which + the server key has been added. + + Make sure to hold onto the temp file reference until the process is + done with it + + :param server_key: the server public key + :type server_key: str + + :param host: the hostname + :type host: str + + :param port: the ssh port + :type port: str + + """ + if port is not None: + host = '%s:%s' % (host, str(port)) + + # Create a temporary server key file + tmp_known_hosts = tempfile.NamedTemporaryFile() + + hostbyname = gethostbyname(host) + + # Add the intended host key + tmp_known_hosts.write('%s,%s %s\n' % (host, hostbyname, server_key)) + + # If we're not in strict mode, add user-configured keys + if os.environ.get('NEPI_STRICT_AUTH_MODE',"").lower() not in ('1','true','on'): + user_hosts_path = '%s/.ssh/known_hosts' % (os.environ.get('HOME',""),) + if os.access(user_hosts_path, os.R_OK): + f = open(user_hosts_path, "r") + tmp_known_hosts.write(f.read()) + f.close() + + tmp_known_hosts.flush() + + return tmp_known_hosts +
+
[docs]def make_control_path(agent, forward_x11): + ctrl_path = "/tmp/nepi_ssh" + + if agent: + ctrl_path +="_a" + + if forward_x11: + ctrl_path +="_x" + + ctrl_path += "-%r@%h:%p" + + return ctrl_path +
+
[docs]def shell_escape(s): + """ Escapes strings so that they are safe to use as command-line + arguments """ + if SHELL_SAFE.match(s): + # safe string - no escaping needed + return s + else: + # unsafe string - escape + def escp(c): + if (32 <= ord(c) < 127 or c in ('\r','\n','\t')) and c not in ("'",'"'): + return c + else: + return "'$'\\x%02x''" % (ord(c),) + s = ''.join(map(escp,s)) + return "'%s'" % (s,) +
+
[docs]def eintr_retry(func): + """Retries a function invocation when a EINTR occurs""" + import functools + @functools.wraps(func) + def rv(*p, **kw): + retry = kw.pop("_retry", False) + for i in xrange(0 if retry else 4): + try: + return func(*p, **kw) + except (select.error, socket.error), args: + if args[0] == errno.EINTR: + continue + else: + raise + except OSError, e: + if e.errno == errno.EINTR: + continue + else: + raise + else: + return func(*p, **kw) + return rv +
+
[docs]def rexec(command, host, user, + port = None, + gwuser = None, + gw = None, + agent = True, + sudo = False, + identity = None, + server_key = None, + env = None, + tty = False, + connect_timeout = 30, + retry = 3, + persistent = True, + forward_x11 = False, + blocking = True, + strict_host_checking = True): + """ + Executes a remote command, returns ((stdout,stderr),process) + """ + + tmp_known_hosts = None + if not gw: + hostip = gethostbyname(host) + else: hostip = None + + args = ['ssh', '-C', + # Don't bother with localhost. Makes test easier + '-o', 'NoHostAuthenticationForLocalhost=yes', + '-o', 'ConnectTimeout=%d' % (int(connect_timeout),), + '-o', 'ConnectionAttempts=3', + '-o', 'ServerAliveInterval=30', + '-o', 'TCPKeepAlive=yes', + '-o', 'Batchmode=yes', + '-l', user, hostip or host] + + if persistent and openssh_has_persist(): + args.extend([ + '-o', 'ControlMaster=auto', + '-o', 'ControlPath=%s' % (make_control_path(agent, forward_x11),), + '-o', 'ControlPersist=60' ]) + + if not strict_host_checking: + # Do not check for Host key. Unsafe. + args.extend(['-o', 'StrictHostKeyChecking=no']) + + if gw: + proxycommand = _proxy_command(gw, gwuser, identity) + args.extend(['-o', proxycommand]) + + if agent: + args.append('-A') + + if port: + args.append('-p%d' % port) + + if identity: + identity = os.path.expanduser(identity) + args.extend(('-i', identity)) + + if tty: + args.append('-t') + args.append('-t') + + if forward_x11: + args.append('-X') + + 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 sudo: + command = "sudo " + command + + args.append(command) + + log_msg = " rexec - host %s - command %s " % (str(host), " ".join(map(str, args))) + + stdout = stderr = stdin = subprocess.PIPE + if forward_x11: + stdout = stderr = stdin = None + + return _retry_rexec(args, log_msg, + stderr = stderr, + stdin = stdin, + stdout = stdout, + env = env, + retry = retry, + tmp_known_hosts = tmp_known_hosts, + blocking = blocking) +
+
[docs]def rcopy(source, dest, + port = None, + gwuser = None, + gw = None, + recursive = False, + identity = None, + server_key = None, + retry = 3, + strict_host_checking = True): + """ + Copies from/to remote sites. + + Source and destination should have the user and host encoded + as per scp specs. + + 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. + """ + + # 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: + 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) + + if gw: + proxycommand = _proxy_command(gw, gwuser, identity) + args.extend(['-o', proxycommand]) + + if recursive: + args.append('-r') + + if identity: + identity = os.path.expanduser(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 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) + + 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) +
+
[docs]def rspawn(command, pidfile, + stdout = '/dev/null', + stderr = STDOUT, + stdin = '/dev/null', + home = None, + create_home = False, + sudo = False, + host = None, + port = None, + user = None, + gwuser = None, + gw = None, + agent = None, + identity = None, + server_key = None, + tty = False, + strict_host_checking = True): + """ + Spawn a remote command such that it will continue working asynchronously in + background. + + :param command: The command to run, it should be a single line. + :type command: str + + :param pidfile: Path to a file where to store the pid and ppid of the + spawned process + :type pidfile: str + + :param stdout: Path to file to redirect standard output. + The default value is /dev/null + :type stdout: str + + :param stderr: Path to file to redirect standard error. + If the special STDOUT value is used, stderr will + be redirected to the same file as stdout + :type stderr: str + + :param stdin: Path to a file with input to be piped into the command's standard input + :type stdin: str + + :param home: Path to working directory folder. + It is assumed to exist unless the create_home flag is set. + :type home: str + + :param create_home: Flag to force creation of the home folder before + running the command + :type create_home: bool + + :param sudo: Flag forcing execution with sudo user + :type sudo: bool + + :rtype: tuple + + (stdout, stderr), process + + Of the spawning process, which only captures errors at spawning time. + Usually only useful for diagnostics. + """ + # Start process in a "daemonized" way, using nohup and heavy + # stdin/out redirection to avoid connection issues + if stderr is STDOUT: + stderr = '&1' + else: + stderr = ' ' + stderr + + daemon_command = '{ { %(command)s > %(stdout)s 2>%(stderr)s < %(stdin)s & } ; echo $! 1 > %(pidfile)s ; }' % { + 'command' : command, + 'pidfile' : shell_escape(pidfile), + 'stdout' : stdout, + 'stderr' : stderr, + 'stdin' : stdin, + } + + cmd = "%(create)s%(gohome)s rm -f %(pidfile)s ; %(sudo)s nohup bash -c %(command)s " % { + 'command' : shell_escape(daemon_command), + 'sudo' : 'sudo -S' if sudo else '', + 'pidfile' : shell_escape(pidfile), + 'gohome' : 'cd %s ; ' % (shell_escape(home),) if home else '', + 'create' : 'mkdir -p %s ; ' % (shell_escape(home),) if create_home and home else '', + } + + (out,err),proc = rexec( + cmd, + host = host, + port = port, + user = user, + gwuser = gwuser, + gw = gw, + agent = agent, + identity = identity, + server_key = server_key, + tty = tty, + strict_host_checking = strict_host_checking , + ) + + if proc.wait(): + raise RuntimeError, "Failed to set up application on host %s: %s %s" % (host, out,err,) + + return ((out, err), proc) +
+@eintr_retry +
[docs]def rgetpid(pidfile, + host = None, + port = None, + user = None, + gwuser = None, + gw = None, + agent = None, + identity = None, + server_key = None, + strict_host_checking = True): + """ + Returns the pid and ppid of a process from a remote file where the + information was stored. + + :param home: Path to directory where the pidfile is located + :type home: str + + :param pidfile: Name of file containing the pid information + :type pidfile: str + + :rtype: int + + A (pid, ppid) tuple useful for calling rstatus and rkill, + or None if the pidfile isn't valid yet (can happen when process is staring up) + + """ + (out,err),proc = rexec( + "cat %(pidfile)s" % { + 'pidfile' : pidfile, + }, + host = host, + port = port, + user = user, + gwuser = gwuser, + gw = gw, + agent = agent, + identity = identity, + server_key = server_key, + strict_host_checking = strict_host_checking + ) + + if proc.wait(): + return None + + if out: + try: + return map(int,out.strip().split(' ',1)) + except: + # Ignore, many ways to fail that don't matter that much + return None +
+@eintr_retry +
[docs]def rstatus(pid, ppid, + host = None, + port = None, + user = None, + gwuser = None, + gw = None, + agent = None, + identity = None, + server_key = None, + strict_host_checking = True): + """ + Returns a code representing the the status of a remote process + + :param pid: Process id of the process + :type pid: int + + :param ppid: Parent process id of process + :type ppid: int + + :rtype: int (One of NOT_STARTED, RUNNING, FINISHED) + + """ + (out,err),proc = rexec( + # 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, + 'pid' : pid, + }, + host = host, + port = port, + user = user, + gwuser = gwuser, + gw = gw, + agent = agent, + identity = identity, + server_key = server_key, + strict_host_checking = strict_host_checking + ) + + if proc.wait(): + return ProcStatus.NOT_STARTED + + status = False + if err: + if err.strip().find("Error, do this: mount -t proc none /proc") >= 0: + status = True + elif out: + status = (out.strip() == 'wait') + else: + return ProcStatus.NOT_STARTED + return ProcStatus.RUNNING if status else ProcStatus.FINISHED +
+@eintr_retry +
[docs]def rkill(pid, ppid, + host = None, + port = None, + user = None, + gwuser = None, + gw = None, + agent = None, + sudo = False, + identity = None, + server_key = None, + nowait = False, + strict_host_checking = True): + """ + Sends a kill signal to a remote process. + + First tries a SIGTERM, and if the process does not end in 10 seconds, + it sends a SIGKILL. + + :param pid: Process id of process to be killed + :type pid: int + + :param ppid: Parent process id of process to be killed + :type ppid: int + + :param sudo: Flag indicating if sudo should be used to kill the process + :type sudo: bool + + """ + subkill = "$(ps --ppid %(pid)d -o pid h)" % { 'pid' : pid } + cmd = """ +SUBKILL="%(subkill)s" ; +%(sudo)s kill -- -%(pid)d $SUBKILL || /bin/true +%(sudo)s kill %(pid)d $SUBKILL || /bin/true +for x in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do + sleep 0.2 + if [ `ps --pid %(pid)d -o pid | grep -c %(pid)d` == '0' ]; then + break + else + %(sudo)s kill -- -%(pid)d $SUBKILL || /bin/true + %(sudo)s kill %(pid)d $SUBKILL || /bin/true + fi + sleep 1.8 +done +if [ `ps --pid %(pid)d -o pid | grep -c %(pid)d` != '0' ]; then + %(sudo)s kill -9 -- -%(pid)d $SUBKILL || /bin/true + %(sudo)s kill -9 %(pid)d $SUBKILL || /bin/true +fi +""" + if nowait: + cmd = "( %s ) >/dev/null 2>/dev/null </dev/null &" % (cmd,) + + (out,err),proc = rexec( + cmd % { + 'ppid' : ppid, + 'pid' : pid, + 'sudo' : 'sudo -S' if sudo else '', + 'subkill' : subkill, + }, + host = host, + port = port, + user = user, + gwuser = gwuser, + gw = gw, + agent = agent, + identity = identity, + server_key = server_key, + strict_host_checking = strict_host_checking + ) + + # wait, don't leave zombies around + proc.wait() + + 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 + bailtime = timelimit + 4 + + if proc.stdin: + # Flush stdio buffer. This might block, if the user has + # been writing to .stdin in an uncontrolled fashion. + proc.stdin.flush() + if input: + write_set.append(proc.stdin) + else: + proc.stdin.close() + + if proc.stdout: + read_set.append(proc.stdout) + stdout = [] + + if proc.stderr: + read_set.append(proc.stderr) + stderr = [] + + input_offset = 0 + while read_set or write_set: + if timeout is not None: + curtime = time.time() + if timeout is None or curtime > timelimit: + if curtime > bailtime: + break + elif curtime > killtime: + signum = signal.SIGKILL + else: + signum = signal.SIGTERM + # Lets kill it + os.kill(proc.pid, signum) + select_timeout = 0.5 + else: + 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: + if e[0] != 4: + 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 + + if proc.stdin in wlist: + # When select has indicated that the file is writable, + # we can write up to PIPE_BUF bytes without risk + # blocking. POSIX defines PIPE_BUF >= 512 + bytes_written = os.write(proc.stdin.fileno(), + buffer(input, input_offset, 512)) + input_offset += bytes_written + + if input_offset >= len(input): + proc.stdin.close() + write_set.remove(proc.stdin) + + if proc.stdout in rlist: + data = os.read(proc.stdout.fileno(), 1024) + if data == "": + proc.stdout.close() + read_set.remove(proc.stdout) + stdout.append(data) + + if proc.stderr in rlist: + data = os.read(proc.stderr.fileno(), 1024) + if data == "": + 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) + if stderr is not None: + stderr = ''.join(stderr) + + # Translate newlines, if requested. We cannot let the file + # object do the translation: It is based on stdio, which is + # impossible to combine with select (unless forcing no + # buffering). + if proc.universal_newlines and hasattr(file, 'newlines'): + if stdout: + stdout = proc._translate_newlines(stdout) + if stderr: + stderr = proc._translate_newlines(stderr) + + if killed and err_on_timeout: + errcode = proc.poll() + raise RuntimeError, ("Operation timed out", errcode, stdout, stderr) + else: + if killed: + proc.poll() + else: + proc.wait() + return (stdout, stderr) + +def _proxy_command(gw, gwuser, gwidentity): + """ + Constructs the SSH ProxyCommand option to add to the SSH command to connect + via a proxy + :param gw: SSH proxy hostname + :type gw: str + + :param gwuser: SSH proxy username + :type gwuser: str + + :param gwidentity: SSH proxy identity file + :type gwidentity: str + + + :rtype: str + + returns the SSH ProxyCommand option. + """ + + proxycommand = 'ProxyCommand=ssh -q ' + if gwidentity: + proxycommand += '-i %s ' % os.path.expanduser(gwidentity) + if gwuser: + proxycommand += '%s' % gwuser + else: + proxycommand += '%r' + proxycommand += '@%s -W %%h:%%p' % gw + + return proxycommand +
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/statfuncs.html b/doc/sphinx/_build/html/_modules/nepi/util/statfuncs.html new file mode 100644 index 00000000..73b5db7a --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/statfuncs.html @@ -0,0 +1,136 @@ + + + + + + + + nepi.util.statfuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.statfuncs

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 math
+import numpy
+from scipy import stats
+
+
[docs]def compute_mean(sample): + # TODO: Discard outliers !!!! + + if not sample: + print " CANNOT COMPUTE STATS for ", sample + return (0, 0, 0, 0) + + x = numpy.array(sample) + + # sample mean and standard deviation + n, min_max, mean, var, skew, kurt = stats.describe(x) + std = math.sqrt(var) + + # for the population mean and std ... + # mean = x.mean() + # std = x.std() + + # Calculate confidence interval t-distribution + ## BUG: Use quantil of NORMAL distribution, not t-student quantil distribution + ci = stats.t.interval(0.95, n-1, loc = mean, scale = std/math.sqrt(n)) + + return (mean, std, ci[0], ci[1]) +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_modules/nepi/util/timefuncs.html b/doc/sphinx/_build/html/_modules/nepi/util/timefuncs.html new file mode 100644 index 00000000..398babe9 --- /dev/null +++ b/doc/sphinx/_build/html/_modules/nepi/util/timefuncs.html @@ -0,0 +1,213 @@ + + + + + + + + nepi.util.timefuncs — NEPI 3.0 documentation + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ +

Source code for nepi.util.timefuncs

+#
+#    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 version 2 as
+#    published by the Free Software Foundation;
+#
+#    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 datetime
+import re
+
+_strf = "%Y%m%d%H%M%S%f"
+_reabs = re.compile("^\d{20}$")
+_rerel = re.compile("^(?P<time>\d+(.\d+)?)(?P<units>h|m|s|ms|us)$")
+
+# Work around to fix "ImportError: Failed to import _strptime because the import lock is held by another thread."
+datetime.datetime.strptime("20120807124732894211", _strf)
+
+
[docs]def stformat(sdate): + """ Constructs a datetime object from a string date with + format YYYYMMddHHMMSSffff + + """ + return datetime.datetime.strptime(sdate, _strf).date() +
+
[docs]def tsformat(date = None): + """ Formats a datetime object to a string with format YYYYMMddHHMMSSffff. + If no date is given, the current date is used. + + """ + if not date: + date = tnow() + + return date.strftime(_strf) +
+
[docs]def tnow(): + """ Returns datetime object with the current time """ + return datetime.datetime.now() +
+
[docs]def tdiff(date1, date2): + """ Returns difference ( date1 - date2 ) as a datetime object, + where date1 and date 2 are datetime objects + + """ + return date1 - date2 +
+def _get_total_seconds(td): + return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 1e6) / 1e6 + +
[docs]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 _get_total_seconds(diff) +
+
[docs]def stabsformat(sdate, dbase = None): + """ Constructs a datetime object from a string date. + The string date can be expressed as an absolute date + ( i.e. format YYYYMMddHHMMSSffff ) or as a relative time + ( e.g. format '5m' or '10s'). + If the date is a relative time and the dbase parameter + is given (dbase must be datetime object), the returned + date will be dbase + sdate. If dbase is None, + current time will be used instead as base time. + + :param date : string date + :type date : date + + """ + + # No date given, return current datetime + if not sdate: + return tnow() + + # Absolute date is given + if _reabs.match(sdate): + return stformat(sdate) + + # Relative time is given + m = _rerel.match(sdate) + if m: + time = float(m.groupdict()['time']) + units = m.groupdict()['units'] + if units == 'h': + delta = datetime.timedelta(hours = time) + elif units == 'm': + delta = datetime.timedelta(minutes = time) + elif units == 's': + delta = datetime.timedelta(seconds = time) + elif units == 'ms': + delta = datetime.timedelta(microseconds = (time*1000)) + else: + delta = datetime.timedelta(microseconds = time) + + if not dbase: + dbase = tnow() + + return dbase + delta + + return None +
+
[docs]def compute_delay_ms(timestamp2, timestamp1): + d1 = datetime.datetime.fromtimestamp(float(timestamp1)) + d2 = datetime.datetime.fromtimestamp(float(timestamp2)) + delay = d2 - d1 + + # round up resolution - round up to miliseconds + return delay.total_seconds() * 1000 +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/_sources/_layout/modules.txt b/doc/sphinx/_build/html/_sources/_layout/modules.txt new file mode 100644 index 00000000..6486b2cf --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/modules.txt @@ -0,0 +1,7 @@ +nepi +==== + +.. toctree:: + :maxdepth: 4 + + nepi diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ccn.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ccn.txt new file mode 100644 index 00000000..4b3bb6b2 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ccn.txt @@ -0,0 +1,22 @@ +nepi.data.processing.ccn package +================================ + +Submodules +---------- + +nepi.data.processing.ccn.parser module +-------------------------------------- + +.. automodule:: nepi.data.processing.ccn.parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.data.processing.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ping.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ping.txt new file mode 100644 index 00000000..56d3574d --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.ping.txt @@ -0,0 +1,22 @@ +nepi.data.processing.ping package +================================= + +Submodules +---------- + +nepi.data.processing.ping.parser module +--------------------------------------- + +.. automodule:: nepi.data.processing.ping.parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.data.processing.ping + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.txt new file mode 100644 index 00000000..6f22a0fa --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.data.processing.txt @@ -0,0 +1,18 @@ +nepi.data.processing package +============================ + +Subpackages +----------- + +.. toctree:: + + nepi.data.processing.ccn + nepi.data.processing.ping + +Module contents +--------------- + +.. automodule:: nepi.data.processing + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.data.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.data.txt new file mode 100644 index 00000000..2841cdc0 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.data.txt @@ -0,0 +1,17 @@ +nepi.data package +================= + +Subpackages +----------- + +.. toctree:: + + nepi.data.processing + +Module contents +--------------- + +.. automodule:: nepi.data + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.execution.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.execution.txt new file mode 100644 index 00000000..c8f46ae0 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.execution.txt @@ -0,0 +1,70 @@ +nepi.execution package +====================== + +Submodules +---------- + +nepi.execution.attribute module +------------------------------- + +.. automodule:: nepi.execution.attribute + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.ec module +------------------------ + +.. automodule:: nepi.execution.ec + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.resource module +------------------------------ + +.. automodule:: nepi.execution.resource + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.runner module +---------------------------- + +.. automodule:: nepi.execution.runner + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.scheduler module +------------------------------- + +.. automodule:: nepi.execution.scheduler + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.tags module +-------------------------- + +.. automodule:: nepi.execution.tags + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.trace module +--------------------------- + +.. automodule:: nepi.execution.trace + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.execution + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.all.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.all.txt new file mode 100644 index 00000000..59459003 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.all.txt @@ -0,0 +1,22 @@ +nepi.resources.all package +========================== + +Submodules +---------- + +nepi.resources.all.collector module +----------------------------------- + +.. automodule:: nepi.resources.all.collector + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.all + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ccn.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ccn.txt new file mode 100644 index 00000000..871cb33f --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ccn.txt @@ -0,0 +1,94 @@ +nepi.resources.linux.ccn package +================================ + +Submodules +---------- + +nepi.resources.linux.ccn.ccnapplication module +---------------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccncat module +-------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccncat + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccncontent module +------------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccncontent + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnd module +------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccnd + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpeek module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpeek + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnping module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpingserver module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpingserver + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpoke module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpoke + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnr module +------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccnr + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.fibentry module +---------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.fibentry + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.netns.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.netns.txt new file mode 100644 index 00000000..a20d9109 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.netns.txt @@ -0,0 +1,30 @@ +nepi.resources.linux.netns package +================================== + +Submodules +---------- + +nepi.resources.linux.netns.netnsclient module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.netns.netnsclient + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.netns.netnsemulation module +------------------------------------------------ + +.. automodule:: nepi.resources.linux.netns.netnsemulation + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.netns + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.ccn.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.ccn.txt new file mode 100644 index 00000000..a6e08684 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.ccn.txt @@ -0,0 +1,70 @@ +nepi.resources.linux.ns3.ccn package +==================================== + +Submodules +---------- + +nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication module +----------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccndceapplication module +-------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccndceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnddceapplication module +--------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnddceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication module +------------------------------------------------------------ + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication module +------------------------------------------------------------ + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication module +--------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication module +------------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ns3.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.txt new file mode 100644 index 00000000..341946ed --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.ns3.txt @@ -0,0 +1,69 @@ +nepi.resources.linux.ns3 package +================================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.linux.ns3.ccn + +Submodules +---------- + +nepi.resources.linux.ns3.fdudptunnel module +------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.fdudptunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3client module +----------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3dceapplication module +------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3dceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3pingdceapplication module +----------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3pingdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3simulation module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3simulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.tuntapfdlink module +-------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.tuntapfdlink + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.txt new file mode 100644 index 00000000..40e4309b --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.linux.txt @@ -0,0 +1,167 @@ +nepi.resources.linux package +============================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.linux.ccn + nepi.resources.linux.netns + nepi.resources.linux.ns3 + +Submodules +---------- + +nepi.resources.linux.application module +--------------------------------------- + +.. automodule:: nepi.resources.linux.application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.channel module +----------------------------------- + +.. automodule:: nepi.resources.linux.channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.debfuncs module +------------------------------------ + +.. automodule:: nepi.resources.linux.debfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.gretunnel module +------------------------------------- + +.. automodule:: nepi.resources.linux.gretunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.interface module +------------------------------------- + +.. automodule:: nepi.resources.linux.interface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.mtr module +------------------------------- + +.. automodule:: nepi.resources.linux.mtr + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.node module +-------------------------------- + +.. automodule:: nepi.resources.linux.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.nping module +--------------------------------- + +.. automodule:: nepi.resources.linux.nping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ping module +-------------------------------- + +.. automodule:: nepi.resources.linux.ping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.route module +--------------------------------- + +.. automodule:: nepi.resources.linux.route + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.rpmfuncs module +------------------------------------ + +.. automodule:: nepi.resources.linux.rpmfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tap module +------------------------------- + +.. automodule:: nepi.resources.linux.tap + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tcpdump module +----------------------------------- + +.. automodule:: nepi.resources.linux.tcpdump + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.traceroute module +-------------------------------------- + +.. automodule:: nepi.resources.linux.traceroute + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tun module +------------------------------- + +.. automodule:: nepi.resources.linux.tun + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tunnel module +---------------------------------- + +.. automodule:: nepi.resources.linux.tunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.udptest module +----------------------------------- + +.. automodule:: nepi.resources.linux.udptest + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.udptunnel module +------------------------------------- + +.. automodule:: nepi.resources.linux.udptunnel + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.netns.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.netns.txt new file mode 100644 index 00000000..eacf7f36 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.netns.txt @@ -0,0 +1,118 @@ +nepi.resources.netns package +============================ + +Submodules +---------- + +nepi.resources.netns.netnsapplication module +-------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsbase module +------------------------------------- + +.. automodule:: nepi.resources.netns.netnsbase + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsclient module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsclient + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsemulation module +------------------------------------------ + +.. automodule:: nepi.resources.netns.netnsemulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsinterface module +------------------------------------------ + +.. automodule:: nepi.resources.netns.netnsinterface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsipv4address module +-------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsipv4address + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsnode module +------------------------------------- + +.. automodule:: nepi.resources.netns.netnsnode + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsnodeinterface module +---------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsnodeinterface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsroute module +-------------------------------------- + +.. automodule:: nepi.resources.netns.netnsroute + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsserver module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsserver + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsswitch module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsswitch + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnswrapper module +---------------------------------------- + +.. automodule:: nepi.resources.netns.netnswrapper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnswrapper_debug module +---------------------------------------------- + +.. automodule:: nepi.resources.netns.netnswrapper_debug + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.netns + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.classes.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.classes.txt new file mode 100644 index 00000000..e489b712 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.classes.txt @@ -0,0 +1,862 @@ +nepi.resources.ns3.classes package +================================== + +Submodules +---------- + +nepi.resources.ns3.classes.aarf_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aarf_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.aarfcd_wifi_manager module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aarfcd_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.adhoc_wifi_mac module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.adhoc_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.aloha_noack_net_device module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aloha_noack_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.amrr_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.amrr_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ap_wifi_mac module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ap_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.arf_wifi_manager module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.arf_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.arp_l3protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.arp_l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.base_station_net_device module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.base_station_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.binary_error_model module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.binary_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.binary_error_sixlow_model module +----------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.binary_error_sixlow_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bridge_channel module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.bridge_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bridge_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.bridge_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bulk_send_application module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.bulk_send_application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.burst_error_model module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.burst_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.cara_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.cara_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_acceleration_mobility_model module +---------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.constant_acceleration_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_position_mobility_model module +------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_position_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_rate_wifi_manager module +------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_rate_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_speed_propagation_delay_model module +------------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_speed_propagation_delay_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_velocity_mobility_model module +------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_velocity_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.cost231propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.cost231propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.csma_channel module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.csma_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.csma_net_device module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.csma_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.drop_tail_queue module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.drop_tail_queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.dsrdsr_routing module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.dsrdsr_routing + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.emu_net_device module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.emu_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_channel module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.error_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_channel_sixlow module +------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.error_channel_sixlow + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_net_device module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.error_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.fd_net_device module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.fd_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.fixed_rss_loss_model module +------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.fixed_rss_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.friis_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.friis_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.gauss_markov_mobility_model module +------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.gauss_markov_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.hierarchical_mobility_model module +------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.hierarchical_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model module +------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.icmpv4l4protocol module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.icmpv4l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.icmpv6l4protocol module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.icmpv6l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ideal_wifi_manager module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ideal_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ipv4l3protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.ipv4l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model module +----------------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.jakes_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.jakes_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model module +------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.list_error_model module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.list_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.log_distance_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.log_distance_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.loopback_net_device module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.loopback_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lr_wpan_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lr_wpan_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_enb_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_enb_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_simple_net_device module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_simple_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_ue_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_ue_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.matrix_propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.matrix_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.mesh_point_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.mesh_point_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.mesh_wifi_interface_mac module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.mesh_wifi_interface_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.minstrel_wifi_manager module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.minstrel_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.multi_model_spectrum_channel module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.multi_model_spectrum_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.nakagami_propagation_loss_model module +----------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.nakagami_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.nist_error_rate_model module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.nist_error_rate_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.node module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.non_communicating_net_device module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.non_communicating_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ocb_wifi_mac module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ocb_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.oh_buildings_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.oh_buildings_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.okumura_hata_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.okumura_hata_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.on_off_application module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.on_off_application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.onoe_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.onoe_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.packet_sink module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.packet_sink + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ping6 module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ping6 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_channel module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_net_device module +----------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_remote_channel module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_remote_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.radvd module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.radvd + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_direction2d_mobility_model module +------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_direction2d_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_propagation_delay_model module +---------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_propagation_delay_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_walk2d_mobility_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_walk2d_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_waypoint_mobility_model module +---------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.range_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.range_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.rate_error_model module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.rate_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.receive_list_error_model module +---------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.receive_list_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.red_queue module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.red_queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.rraa_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.rraa_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.simple_channel module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.simple_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.simple_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.simple_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.single_model_spectrum_channel module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.single_model_spectrum_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.six_low_pan_net_device module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.six_low_pan_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.sta_wifi_mac module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.sta_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model module +----------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.subscriber_station_net_device module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.subscriber_station_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.tap_bridge module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.tap_bridge + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.tcp_l4protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.tcp_l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.three_log_distance_propagation_loss_model module +--------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.three_log_distance_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model module +----------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.uan_channel module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.uan_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_client module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_echo_client module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_echo_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_echo_server module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_echo_server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_l4protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.udp_l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_server module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_trace_client module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_trace_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.v4ping module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.v4ping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.virtual_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.virtual_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.waypoint_mobility_model module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.wifi_net_device module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.wifi_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_error_rate_model module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_error_rate_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_wifi_channel module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_wifi_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_wifi_phy module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_wifi_phy + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.ns3.classes + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.txt new file mode 100644 index 00000000..94356ab8 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.ns3.txt @@ -0,0 +1,269 @@ +nepi.resources.ns3 package +========================== + +Subpackages +----------- + +.. toctree:: + + nepi.resources.ns3.classes + +Submodules +---------- + +nepi.resources.ns3.ns3application module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3arpl3protocol module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3arpl3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3base module +--------------------------------- + +.. automodule:: nepi.resources.ns3.ns3base + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3ccndceapplication module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3ccndceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3channel module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3client module +----------------------------------- + +.. automodule:: nepi.resources.ns3.ns3client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3dceapplication module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3dceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3dcehelper module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3dcehelper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3errormodel module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3errormodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3errorratemodel module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3errorratemodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3fdnetdevice module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3fdnetdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3icmpv4l4protocol module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3icmpv4l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3ipv4l3protocol module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3ipv4l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3mobilitymodel module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3mobilitymodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3netdevice module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3netdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3node module +--------------------------------- + +.. automodule:: nepi.resources.ns3.ns3node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3pipechanel module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3pipechanel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3propagationdelaymodel module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3propagationdelaymodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3propagationlossmodel module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3propagationlossmodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3queue module +---------------------------------- + +.. automodule:: nepi.resources.ns3.ns3queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3route module +---------------------------------- + +.. automodule:: nepi.resources.ns3.ns3route + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3server module +----------------------------------- + +.. automodule:: nepi.resources.ns3.ns3server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3simulation module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3simulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifichannel module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3wifichannel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifimac module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifimac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifinetdevice module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifinetdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifiphy module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifiphy + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifiremotestationmanager module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3wifiremotestationmanager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wrapper module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wrapper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wrapper_debug module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wrapper_debug + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.resource_manager_generator module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.resource_manager_generator + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.omf.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.omf.txt new file mode 100644 index 00000000..7dd222ee --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.omf.txt @@ -0,0 +1,118 @@ +nepi.resources.omf package +========================== + +Submodules +---------- + +nepi.resources.omf.application module +------------------------------------- + +.. automodule:: nepi.resources.omf.application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.channel module +--------------------------------- + +.. automodule:: nepi.resources.omf.channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.interface module +----------------------------------- + +.. automodule:: nepi.resources.omf.interface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.messages_5_4 module +-------------------------------------- + +.. automodule:: nepi.resources.omf.messages_5_4 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.messages_6 module +------------------------------------ + +.. automodule:: nepi.resources.omf.messages_6 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.node module +------------------------------ + +.. automodule:: nepi.resources.omf.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf5_api module +---------------------------------- + +.. automodule:: nepi.resources.omf.omf5_api + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf6_api module +---------------------------------- + +.. automodule:: nepi.resources.omf.omf6_api + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf6_parser module +------------------------------------- + +.. automodule:: nepi.resources.omf.omf6_parser + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_api_factory module +----------------------------------------- + +.. automodule:: nepi.resources.omf.omf_api_factory + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_client module +------------------------------------ + +.. automodule:: nepi.resources.omf.omf_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_resource module +-------------------------------------- + +.. automodule:: nepi.resources.omf.omf_resource + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.wilabt_node module +------------------------------------- + +.. automodule:: nepi.resources.omf.wilabt_node + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.omf + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.ns3.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.ns3.txt new file mode 100644 index 00000000..a8759d48 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.ns3.txt @@ -0,0 +1,30 @@ +nepi.resources.planetlab.ns3 package +==================================== + +Submodules +---------- + +nepi.resources.planetlab.ns3.fdudptunnel module +----------------------------------------------- + +.. automodule:: nepi.resources.planetlab.ns3.fdudptunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.ns3.tuntapfdlink module +------------------------------------------------ + +.. automodule:: nepi.resources.planetlab.ns3.tuntapfdlink + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.openvswitch.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.openvswitch.txt new file mode 100644 index 00000000..edbb21a2 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.openvswitch.txt @@ -0,0 +1,30 @@ +nepi.resources.planetlab.openvswitch package +============================================ + +Submodules +---------- + +nepi.resources.planetlab.openvswitch.ovs module +----------------------------------------------- + +.. automodule:: nepi.resources.planetlab.openvswitch.ovs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.openvswitch.ovsport module +--------------------------------------------------- + +.. automodule:: nepi.resources.planetlab.openvswitch.ovsport + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab.openvswitch + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.txt new file mode 100644 index 00000000..9fde12c9 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.planetlab.txt @@ -0,0 +1,70 @@ +nepi.resources.planetlab package +================================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.planetlab.ns3 + nepi.resources.planetlab.openvswitch + +Submodules +---------- + +nepi.resources.planetlab.node module +------------------------------------ + +.. automodule:: nepi.resources.planetlab.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.plcapi module +-------------------------------------- + +.. automodule:: nepi.resources.planetlab.plcapi + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.sfa_node module +---------------------------------------- + +.. automodule:: nepi.resources.planetlab.sfa_node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.tap module +----------------------------------- + +.. automodule:: nepi.resources.planetlab.tap + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.tun module +----------------------------------- + +.. automodule:: nepi.resources.planetlab.tun + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.vroute module +-------------------------------------- + +.. automodule:: nepi.resources.planetlab.vroute + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.resources.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.txt new file mode 100644 index 00000000..4c1fcfc2 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.resources.txt @@ -0,0 +1,22 @@ +nepi.resources package +====================== + +Subpackages +----------- + +.. toctree:: + + nepi.resources.all + nepi.resources.linux + nepi.resources.netns + nepi.resources.ns3 + nepi.resources.omf + nepi.resources.planetlab + +Module contents +--------------- + +.. automodule:: nepi.resources + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.txt new file mode 100644 index 00000000..aa1d5d30 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.txt @@ -0,0 +1,20 @@ +nepi package +============ + +Subpackages +----------- + +.. toctree:: + + nepi.data + nepi.execution + nepi.resources + nepi.util + +Module contents +--------------- + +.. automodule:: nepi + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.util.parsers.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.util.parsers.txt new file mode 100644 index 00000000..34888c17 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.util.parsers.txt @@ -0,0 +1,22 @@ +nepi.util.parsers package +========================= + +Submodules +---------- + +nepi.util.parsers.xml_parser module +----------------------------------- + +.. automodule:: nepi.util.parsers.xml_parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.util.parsers + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/_layout/nepi.util.txt b/doc/sphinx/_build/html/_sources/_layout/nepi.util.txt new file mode 100644 index 00000000..cf0bc639 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/_layout/nepi.util.txt @@ -0,0 +1,141 @@ +nepi.util package +================= + +Subpackages +----------- + +.. toctree:: + + nepi.util.parsers + +Submodules +---------- + +nepi.util.environ module +------------------------ + +.. automodule:: nepi.util.environ + :members: + :undoc-members: + :show-inheritance: + +nepi.util.execfuncs module +-------------------------- + +.. automodule:: nepi.util.execfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.guid module +--------------------- + +.. automodule:: nepi.util.guid + :members: + :undoc-members: + :show-inheritance: + +nepi.util.logger module +----------------------- + +.. automodule:: nepi.util.logger + :members: + :undoc-members: + :show-inheritance: + +nepi.util.manifoldapi module +---------------------------- + +.. automodule:: nepi.util.manifoldapi + :members: + :undoc-members: + :show-inheritance: + +nepi.util.netgraph module +------------------------- + +.. automodule:: nepi.util.netgraph + :members: + :undoc-members: + :show-inheritance: + +nepi.util.parallel module +------------------------- + +.. automodule:: nepi.util.parallel + :members: + :undoc-members: + :show-inheritance: + +nepi.util.plotter module +------------------------ + +.. automodule:: nepi.util.plotter + :members: + :undoc-members: + :show-inheritance: + +nepi.util.rmatcher module +------------------------- + +.. automodule:: nepi.util.rmatcher + :members: + :undoc-members: + :show-inheritance: + +nepi.util.serializer module +--------------------------- + +.. automodule:: nepi.util.serializer + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sfaapi module +----------------------- + +.. automodule:: nepi.util.sfaapi + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sfarspec_proc module +------------------------------ + +.. automodule:: nepi.util.sfarspec_proc + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sshfuncs module +------------------------- + +.. automodule:: nepi.util.sshfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.statfuncs module +-------------------------- + +.. automodule:: nepi.util.statfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.timefuncs module +-------------------------- + +.. automodule:: nepi.util.timefuncs + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.util + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_build/html/_sources/index.txt b/doc/sphinx/_build/html/_sources/index.txt new file mode 100644 index 00000000..6cc4c839 --- /dev/null +++ b/doc/sphinx/_build/html/_sources/index.txt @@ -0,0 +1,91 @@ +.. Nepi documentation master file, created by + sphinx-quickstart on Tue Mar 26 11:36:35 2013. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +NEPI modules +============ + +This page documents the NEPI source code. It presents the NEPI core modules, the Platform resource modules (i.e. drivers to manage platforms), and other miscellaneous classes. + +Core modules +------------ + + * ExperimentController API + + * :mod:`ExperimentController ` + + * ResourceManager API + + * :mod:`ResourceManager ` + + * Attribute module + + * :mod:`Attribute ` + + * Trace module + + * :mod:`Trace ` + + * Runner module + + * :mod:`ExperimentRunner ` + + * Scheduler module + + * :mod:`Scheduler ` + + + +Platform modules +---------------- + + * Live Experiments + + * Linux testbeds + + * :mod:`Linux ` + + * PlanetLab testbeds + + * :mod:`PlanetLab ` + + * OMF testbed + + * :mod:`OMF ` + + * Simulated Experiments + + * ns-3 simulator + + * :mod:`ns-3 ` + + * :mod:`ns-3 in Linux hosts ` + + * Emulated Experiments + + * DCE emulation extension + + * :mod:`DCE Application ` + + * :mod:`DCE Linux Application ` + + * NetNS emulator + + * :mod:`NetNS ` + +Miscellaneous modules +--------------------- + + * :mod:`Util ` + +.. toctree:: + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/sphinx/_build/html/_static/ajax-loader.gif b/doc/sphinx/_build/html/_static/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..61faf8cab23993bd3e1560bff0668bd628642330 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&6%4J(nYONL^}d+=#lXOz_@CR)H6+;CF~HSG&w!bcfq_AXfq{Vm zWH!t(Aic1sB! zcCYN`9t=>U8IjE~0h#01qo^R=!n1qBvo4oHr@)W|LrH}MAJ=H96*V$jOYgr;lwfaA zxGwRi%~^7js*08n)F38ggUmQ~87XU@ay&8N%#<*Fw$@}BzAut~A3dECXRI!e`M`B% z^In-_E3}y+--`cXY(C6yv@%6%{(csyQOw9j8FTDPQq?|X)Hd?%^%_IjQo@w4CEj#5hBAqnPpK=gjmV0R+*tkWC6L)Vg{XUhk(O?5-=kEErnqDw-*pSUJ0tNL4PQjaV zLStt!zPnXeFg2m$ZsMG~CevCS-HsZFOh}l$jggn-kb}T%!-hlG&P{|F!;WE$!70zx zsZLksXkM4&;5e+%cf62~#n52osSWD_Bn~A?u!r4R%A`=5B+)c4T5tjbgEc7OfB^vY CAl1tN literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/html/_static/basic.css b/doc/sphinx/_build/html/_static/basic.css new file mode 100644 index 00000000..967e36ce --- /dev/null +++ b/doc/sphinx/_build/html/_static/basic.css @@ -0,0 +1,537 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width: 30px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/doc/sphinx/_build/html/_static/comment-bright.png b/doc/sphinx/_build/html/_static/comment-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..551517b8c83b76f734ff791f847829a760ad1903 GIT binary patch literal 3500 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 A2LJ#7 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/html/_static/comment.png b/doc/sphinx/_build/html/_static/comment.png new file mode 100644 index 0000000000000000000000000000000000000000..92feb52b8824c6b0f59b658b1196c61de9162a95 GIT binary patch literal 3445 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 Xn!ZpXD%P(H00000NkvXXu0mjfU}oXkrG1_sUo zkH}&M25w;xW@MN(M}mQYfxX1j*OmPSBd@5KxpVcFGYkw2k|nMYCC>S|xv6<249-QV zi6yBi3gww484B*6z5(HleBulY4CbCLjv*Y^m-brnF(@z`iu(6IPFOwmN=1*JiUaeM zsAz^JAt@F`ro|SnGAHKguFn5FVdQ&MBb@0FCW8 AtN;K2 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/html/_static/doctools.js b/doc/sphinx/_build/html/_static/doctools.js new file mode 100644 index 00000000..c5455c90 --- /dev/null +++ b/doc/sphinx/_build/html/_static/doctools.js @@ -0,0 +1,238 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s == 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node) { + if (node.nodeType == 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/doc/sphinx/_build/html/_static/down-pressed.png b/doc/sphinx/_build/html/_static/down-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..6f7ad782782e4f8e39b0c6e15c7344700cdd2527 GIT binary patch literal 368 zcmV-$0gwKPP)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01ejw01ejxLMWSf00007bV*G`2igY; z04)}F5=J8c008hwL_t(I%gxduPXj>^1>o=6N-Q8ND?p%08Vq(59HL^wzd%>Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01ejw01ejxLMWSf00007bV*G`2igY# z7a|D7?NxgK008SrL_t(I%gxfEPD4Qu1<>=_N-Q8ND?p%`G#EYrhp6H&&{g~flB5EU zUMz-w1XPeF)Bz7OOR0ToF^ zK~y-)t&y=x#6S>+ze#c^Cm0A@3nC^Qc-YxlS_y(!_%MPYX?%tQUqG?c_Yee?bf*#1 zM8xI<&s__-Be}$Q5&vp-nEB_M9T^M;7g?4a&`yV87@h+VMUiQ%D2mL)$(aOso};w} zKt!gaCb5WM+cvK2mQbb!T5FOdDK!)&BJ_H_$}Udv5d=XaL7kjpVUb`~a}oHyUo-I? zV-~P1tC;}c(4t^u$Y zmtmj^o`nO-iXV{!3p~t8{-jMt;Wt0000 to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context ? context.ownerDocument || context : document ); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.7.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.add( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.fireWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).off( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery.Callbacks( "once memory" ); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array, i ) { + var len; + + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +// String to Object flags format cache +var flagsCache = {}; + +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} + +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( flags ) { + + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; + + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + fired = true; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + return this; + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); + + + + +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + tds, + events, + eventName, + i, + isSupported, + div = document.createElement( "div" ), + documentElement = document.documentElement; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + pixelMargin: true + }; + + // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead + jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: 1, + change: 1, + focusin: 1 + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + fragment.removeChild( div ); + + // Null elements to avoid leaks in IE + fragment = select = opt = div = input = null; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, outer, inner, table, td, offsetSupport, + marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, + paddingMarginBorderVisibility, paddingMarginBorder, + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + conMarginTop = 1; + paddingMarginBorder = "padding:0;margin:0;border:"; + positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; + paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; + style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; + html = "
" + + "" + + "
"; + + container = document.createElement("div"); + container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
t
"; + tds = div.getElementsByTagName( "td" ); + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( window.getComputedStyle ) { + div.innerHTML = ""; + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.style.width = "2px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.width = div.style.padding = "1px"; + div.style.border = 0; + div.style.overflow = "hidden"; + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + } + + div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; + div.innerHTML = html; + + outer = div.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; + + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; + + inner.style.position = "fixed"; + inner.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + if ( window.getComputedStyle ) { + div.style.marginTop = "1%"; + support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; + } + + if ( typeof container.style.zoom !== "undefined" ) { + container.style.zoom = 1; + } + + body.removeChild( container ); + marginDiv = div = container = null; + + jQuery.extend( support, offsetSupport ); + }); + + return support; +})(); + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, + isEvents = name === "events"; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = ++jQuery.uuid; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + privateCache = thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ internalKey ] : internalKey; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the cache and need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ internalKey ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + } else { + elem[ internalKey ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + jQuery.isNumeric( data ) ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + hooks = {}; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise( object ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = ( value || "" ).split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + attrNames = value.toLowerCase().split( rspace ); + l = attrNames.length; + + for ( ; i < l; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); + + + + +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + var attrs = elem.attributes || {}; + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || (attrs.id || {}).value === m[2]) && + (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + quick: selector && quickParse( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, origType, namespaces, origCount, + j, events, special, handle, eventType, handleObj; + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var type = event.type || event, + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + old = null; + for ( ; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = [], + i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + // Pregenerate a single jQuery object for reuse with .is() + jqcur = jQuery(this); + jqcur.context = this.ownerDocument || this; + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process events on disabled elements (#6911, #8165) + if ( cur.disabled !== true ) { + selMatch = {}; + matches = []; + jqcur[0] = cur; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = ( + handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) + ); + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { + event.metaKey = event.ctrlKey; + } + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady + }, + + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + ret; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + form._submit_attached = true; + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = true; + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( var type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rReturn = /\r\n/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context, seed ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set, seed ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set, i, len, match, type, left; + + if ( !expr ) { + return []; + } + + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + type, found, item, filter, left, + i, pass, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + filter = Expr.filter[ type ]; + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + pass = not ^ found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + first = match[2]; + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + doneName = match[0]; + parent = elem.parentNode; + + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent[ expando ] = doneName; + } + + diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + !type && Sizzle.attr ? + result != null : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} +// Expose origPOS +// "global" as in regardless of relation to brackets/parens +Expr.match.globalPOS = origPOS; + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context, seed ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet, seed ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.globalPOS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array (deprecated as of jQuery 1.7) + if ( jQuery.isArray( selectors ) ) { + var level = 1; + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { + + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} + + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*", "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + + + +
+
+ + + + + +
+
+ +
+
+
+
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | X + +
+

A

+ + + +
+ +
abort (nepi.execution.ec.ExperimentController attribute) +
+ +
+ +
(nepi.execution.ec.FailureManager attribute) +
+ +
+ +
add_edge() (nepi.util.netgraph.NetGraph method) +
+ + +
add_node() (nepi.util.netgraph.NetGraph method) +
+ + +
add_resource_to_slice() (nepi.util.manifoldapi.MANIFOLDAPI method) +
+ +
+ +
(nepi.util.sfaapi.SFAAPI method) +
+ +
+ +
add_resource_to_slice_batch() (nepi.util.sfaapi.SFAAPI method) +
+ + +
add_set_hook() (nepi.resources.omf.application.OMFApplication method) +
+ + +
add_set_hooks() (nepi.resources.linux.interface.LinuxInterface method) +
+ + +
add_slice_nodes() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
ADHOC (nepi.util.netgraph.TopologyType attribute) +
+ + +
alias_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
+ + +
ALL (nepi.execution.trace.TraceAttr attribute) +
+ + +
allowed (nepi.execution.attribute.Attribute attribute) +
+ + +
allowed_types (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
+ + +
AMtoGateway (nepi.resources.omf.omf_resource.ResourceGateway attribute) +
+ + +
annotate_cn_graph() (in module nepi.data.processing.ccn.parser) +
+ +
+ +
(in module nepi.data.processing.ping.parser) +
+ +
+
+ +
annotate_cn_node() (in module nepi.data.processing.ccn.parser) +
+ +
+ +
(in module nepi.data.processing.ping.parser) +
+ +
+ +
annotate_edge() (nepi.util.netgraph.NetGraph method) +
+ + +
annotate_edge_net() (nepi.util.netgraph.NetGraph method) +
+ + +
annotate_node() (nepi.util.netgraph.NetGraph method) +
+ + +
annotate_node_ip() (nepi.util.netgraph.NetGraph method) +
+ + +
api (nepi.resources.planetlab.plcapi.PLCAPI attribute) +
+ +
+ +
(nepi.util.manifoldapi.MANIFOLDAPI attribute) +
+ +
+ +
app_home (nepi.resources.linux.application.LinuxApplication attribute) +
+ + +
app_home() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ +
+ +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ +
+ +
arp (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
+ + +
ascii_helper_uuid (nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
+ + +
assign_controller() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
+ + +
assign_p2p_ips() (nepi.util.netgraph.NetGraph method) +
+ + +
attach() (nepi.util.parallel.WorkerThread method) +
+ + +
Attribute (class in nepi.execution.attribute) +
+ +
+ +

B

+ + + +
+ +
backticks() (in module nepi.util.environ) +
+ + +
BaseOMFClient (class in nepi.resources.omf.omf_client) +
+ + +
bin_dir (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
blacklist_host() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
blacklist_resource() (nepi.util.sfaapi.SFAAPI method) +
+ +
+ +
blacklisted() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ +
+ +
(nepi.util.sfaapi.SFAAPI method) +
+ +
+ +
Bool (nepi.execution.attribute.Types attribute) +
+ + +
build() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
build_sfa_rspec() (nepi.util.sfarspec_proc.SfaRSpecProcessing method) +
+ +
+ +

C

+ + + +
+ +
ccn_client_helper_uuid (nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication attribute) +
+ + +
ccn_client_lock (nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication attribute) +
+ + +
ccn_consumers() (in module nepi.data.processing.ccn.parser) +
+ + +
ccn_producers() (in module nepi.data.processing.ccn.parser) +
+ + +
ccnd (nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication attribute) +
+ +
+ +
(nepi.resources.linux.ccn.ccncontent.LinuxCCNContent attribute) +
+ + +
(nepi.resources.linux.ccn.ccnr.LinuxCCNR attribute) +
+ + +
(nepi.resources.linux.ccn.fibentry.LinuxFIBEntry attribute) +
+ +
+ +
ccnpingserver (nepi.resources.linux.ccn.ccnping.LinuxCCNPing attribute) +
+ + +
ccnr (nepi.resources.linux.ccn.ccncontent.LinuxCCNContent attribute) +
+ + +
channel (nepi.resources.linux.interface.LinuxInterface attribute) +
+ +
+ +
(nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
+ + +
(nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel attribute) +
+ + +
(nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel attribute) +
+ + +
(nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy attribute) +
+ + +
(nepi.resources.omf.interface.OMFWifiInterface attribute) +
+ +
+ +
ChannelToFreq (nepi.resources.omf.channel.OMFChannel attribute) +
+ + +
check_deploy() (nepi.resources.omf.application.OMFApplication method) +
+ +
+ +
(nepi.resources.omf.interface.OMFWifiInterface method) +
+ +
+ +
check_errors() (nepi.resources.linux.node.LinuxNode method) +
+ + +
check_mailbox() (nepi.resources.omf.omf6_api.OMF6API method) +
+ +
+ +
(nepi.resources.omf.omf6_parser.OMF6Parser method) +
+ + +
(nepi.resources.omf.omf_client.OMFClient method) +
+ +
+ +
check_output() (nepi.resources.linux.node.LinuxNode method) +
+ + +
check_ready() (nepi.resources.omf.omf6_api.OMF6API method) +
+ + +
check_release() (nepi.resources.omf.application.OMFApplication method) +
+ +
+ +
(nepi.resources.omf.interface.OMFWifiInterface method) +
+ +
+ +
check_sliver_ovs() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
+ + +
check_start() (nepi.resources.omf.application.OMFApplication method) +
+ + +
check_state_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
+ +
+ +
(nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
+ +
+ +
check_status() (nepi.resources.linux.tap.LinuxTap method) +
+ +
+ +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ +
+ +
clean_experiment() (nepi.resources.linux.node.LinuxNode method) +
+ + +
clean_home() (nepi.resources.linux.node.LinuxNode method) +
+ + +
clean_processes() (nepi.resources.linux.node.LinuxNode method) +
+ + +
client (nepi.resources.netns.netnsemulation.NetNSEmulation attribute) +
+ +
+ +
(nepi.resources.ns3.ns3simulation.NS3Simulation attribute) +
+ +
+ +
clone_command() (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ + +
close_socket() (in module nepi.resources.ns3.ns3server) +
+ + +
clsinit() (in module nepi.execution.resource) +
+ +
+ +
clsinit_copy() (in module nepi.execution.resource) +
+ + +
Collector (class in nepi.resources.all.collector) +
+ + +
compute_delay_ms() (in module nepi.util.timefuncs) +
+ + +
compute_mean() (in module nepi.util.statfuncs) +
+ + +
conditions (nepi.execution.resource.ResourceManager attribute) +
+ + +
configure() (nepi.execution.resource.ResourceManager method) +
+ +
+ +
(nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ + +
(nepi.resources.omf.omf5_api.OMF5API method) +
+ +
+ +
configure_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
+ +
+ +
(nepi.resources.omf.messages_6.MessageHandler method) +
+ +
+ +
configure_iface() (nepi.resources.omf.interface.OMFWifiInterface method) +
+ + +
configure_ip() (nepi.resources.omf.interface.OMFWifiInterface method) +
+ + +
configure_on_omf5() (nepi.resources.omf.interface.OMFWifiInterface method) +
+ + +
configure_on_omf6() (nepi.resources.omf.interface.OMFWifiInterface method) +
+ + +
connected (nepi.resources.netns.netnsbase.NetNSBase attribute) +
+ +
+ +
(nepi.resources.ns3.ns3base.NS3Base attribute) +
+ +
+ +
connections (nepi.execution.resource.ResourceManager attribute) +
+ + +
Construct (nepi.execution.attribute.Flags attribute) +
+ + +
copy() (nepi.resources.linux.node.LinuxNode method) +
+ + +
CORRUPTFILE (nepi.resources.linux.node.ExitCode attribute) +
+ + +
CREATE (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
+ +
+ +
(nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
+ +
+ +
create() (nepi.execution.resource.ResourceFactory class method) +
+ +
+ +
(nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
+ + +
(nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ + +
(nepi.resources.netns.netnsclient.NetNSClient method) +
+ + +
(nepi.resources.netns.netnsemulation.NetNSEmulation method) +
+ + +
(nepi.resources.netns.netnswrapper.NetNSWrapper method) +
+ + +
(nepi.resources.ns3.ns3client.NS3Client method) +
+ + +
(nepi.resources.ns3.ns3simulation.NS3Simulation method) +
+ + +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ + +
(nepi.resources.omf.omf_client.OMFClient method) +
+ +
+ +
create_and_enroll_topic() (nepi.resources.omf.omf6_api.OMF6API method) +
+ + +
create_api() (nepi.resources.omf.omf_api_factory.OMFAPIFactory class method) +
+ +
+ +
(nepi.resources.planetlab.plcapi.PLCAPIFactory class method) +
+ +
+ +
create_bridge() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
+ + +
create_function() (nepi.resources.omf.messages_6.MessageHandler method) +
+ + +
create_ns3_rms() (in module nepi.resources.ns3.resource_manager_generator) +
+ + +
create_port() (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ + +
create_socket() (in module nepi.resources.netns.netnsserver) +
+ + +
Credential (nepi.execution.attribute.Flags attribute) +
+ +
+ +

D

+ + + +
+ +
dce_application_lock (nepi.resources.ns3.ns3dcehelper.NS3DceHelper attribute) +
+ + +
dce_application_uuid (nepi.resources.ns3.ns3dcehelper.NS3DceHelper attribute) +
+ + +
dce_helper (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
dce_manager_lock (nepi.resources.ns3.ns3dcehelper.NS3DceHelper attribute) +
+ + +
dce_manager_uuid (nepi.resources.ns3.ns3dcehelper.NS3DceHelper attribute) +
+ + +
dce_repo (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
dce_src_location (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
dce_version (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
dceapplications (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
+ + +
DEBIAN (nepi.resources.linux.node.OSType attribute) +
+ + +
debug() (nepi.util.logger.Logger method) +
+ + +
debuger (nepi.resources.netns.netnswrapper.NetNSWrapper attribute) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
+ +
+ +
default (nepi.execution.attribute.Attribute attribute) +
+ + +
del_edge_annotation() (nepi.util.netgraph.NetGraph method) +
+ + +
del_node_annotation() (nepi.util.netgraph.NetGraph method) +
+ + +
delete() (nepi.resources.omf.omf5_api.OMF5API method) +
+ +
+ +
(nepi.resources.omf.omf_client.OMFClient method) +
+ +
+ +
delete_slice_node() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
DEPLOY (nepi.execution.resource.ResourceAction attribute) +
+ + +
deploy() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ +
+ +
deploy_with_conditions() (nepi.execution.resource.ResourceManager method) +
+ + +
Design (nepi.execution.attribute.Flags attribute) +
+ + +
destroy() (nepi.util.parallel.ParallelRun method) +
+ + +
device (nepi.resources.linux.route.LinuxRoute attribute) +
+ +
+ +
(nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel attribute) +
+ + +
(nepi.resources.ns3.ns3queue.NS3BaseQueue attribute) +
+ + +
(nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac attribute) +
+ + +
(nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy attribute) +
+ + +
(nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager attribute) +
+ +
+ +
device_helper_uuid (nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
+ + +
devices (nepi.resources.ns3.ns3channel.NS3BaseChannel attribute) +
+ +
+ +
(nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
+ + +
(nepi.resources.ns3.ns3pipechanel.NS3BasePipeChannel attribute) +
+ +
+ +
disconnect() (nepi.resources.omf.omf5_api.OMF5API method) +
+ +
+ +
(nepi.resources.omf.omf6_api.OMF6API method) +
+ +
+ +
discover() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ +
+ +
discover_time (nepi.execution.resource.ResourceManager attribute) +
+ +
+ +
DISCOVERED (nepi.execution.resource.ResourceState attribute) +
+ + +
do_configure() (nepi.execution.resource.ResourceManager method) +
+ + +
do_connect() (nepi.execution.resource.ResourceManager method) +
+ + +
do_deploy() (nepi.execution.resource.ResourceManager method) +
+ +
+ +
(nepi.resources.all.collector.Collector method) +
+ + +
(nepi.resources.linux.application.LinuxApplication method) +
+ + +
(nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication method) +
+ + +
(nepi.resources.linux.ccn.ccncat.LinuxCCNCat method) +
+ + +
(nepi.resources.linux.ccn.ccncontent.LinuxCCNContent method) +
+ + +
(nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
+ + +
(nepi.resources.linux.ccn.ccnpeek.LinuxCCNPeek method) +
+ + +
(nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer method) +
+ + +
(nepi.resources.linux.ccn.ccnpoke.LinuxCCNPoke method) +
+ + +
(nepi.resources.linux.ccn.ccnr.LinuxCCNR method) +
+ + +
(nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
+ + +
(nepi.resources.linux.interface.LinuxInterface method) +
+ + +
(nepi.resources.linux.mtr.LinuxMtr method) +
+ + +
(nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ + +
(nepi.resources.linux.node.LinuxNode method) +
+ + +
(nepi.resources.linux.nping.LinuxNPing method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ + +
(nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink method) +
+ + +
(nepi.resources.linux.ping.LinuxPing method) +
+ + +
(nepi.resources.linux.route.LinuxRoute method) +
+ + +
(nepi.resources.linux.tap.LinuxTap method) +
+ + +
(nepi.resources.linux.tcpdump.LinuxTcpdump method) +
+ + +
(nepi.resources.linux.traceroute.LinuxTraceroute method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptest.LinuxUdpTest method) +
+ + +
(nepi.resources.netns.netnsbase.NetNSBase method) +
+ + +
(nepi.resources.ns3.ns3base.NS3Base method) +
+ + +
(nepi.resources.omf.application.OMFApplication method) +
+ + +
(nepi.resources.omf.channel.OMFChannel method) +
+ + +
(nepi.resources.omf.interface.OMFWifiInterface method) +
+ + +
(nepi.resources.omf.node.OMFNode method) +
+ + +
(nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ + +
(nepi.resources.planetlab.vroute.PlanetlabVroute method) +
+ +
+ +
do_disconnect() (nepi.execution.resource.ResourceManager method) +
+ + +
do_discover() (nepi.execution.resource.ResourceManager method) +
+ +
+ +
(nepi.resources.linux.interface.LinuxInterface method) +
+ + +
(nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ + +
(nepi.resources.planetlab.node.PlanetlabNode method) +
+ + +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
+ +
+ +
do_fail() (nepi.execution.resource.ResourceManager method) +
+ + +
do_provision() (nepi.execution.resource.ResourceManager method) +
+ +
+ +
(nepi.resources.all.collector.Collector method) +
+ + +
(nepi.resources.linux.application.LinuxApplication method) +
+ + +
(nepi.resources.linux.interface.LinuxInterface method) +
+ + +
(nepi.resources.linux.node.LinuxNode method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.netns.netnsbase.NetNSBase method) +
+ + +
(nepi.resources.ns3.ns3base.NS3Base method) +
+ + +
(nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ + +
(nepi.resources.planetlab.node.PlanetlabNode method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ + +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
+ +
+ +
do_release() (nepi.execution.resource.ResourceManager method) +
+ +
+ +
(nepi.resources.all.collector.Collector method) +
+ + +
(nepi.resources.linux.application.LinuxApplication method) +
+ + +
(nepi.resources.linux.interface.LinuxInterface method) +
+ + +
(nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ + +
(nepi.resources.linux.node.LinuxNode method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ + +
(nepi.resources.linux.tap.LinuxTap method) +
+ + +
(nepi.resources.omf.application.OMFApplication method) +
+ + +
(nepi.resources.omf.channel.OMFChannel method) +
+ + +
(nepi.resources.omf.interface.OMFWifiInterface method) +
+ + +
(nepi.resources.omf.node.OMFNode method) +
+ + +
(nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ + +
(nepi.resources.planetlab.node.PlanetlabNode method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ + +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
+ + +
(nepi.resources.planetlab.vroute.PlanetlabVroute method) +
+ +
+ +
do_reserve() (nepi.execution.resource.ResourceManager method) +
+ + +
do_start() (nepi.execution.resource.ResourceManager method) +
+ +
+ +
(nepi.resources.linux.application.LinuxApplication method) +
+ + +
(nepi.resources.linux.ccn.ccncontent.LinuxCCNContent method) +
+ + +
(nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
+ + +
(nepi.resources.linux.ccn.ccnping.LinuxCCNPing method) +
+ + +
(nepi.resources.linux.ccn.ccnr.LinuxCCNR method) +
+ + +
(nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
+ + +
(nepi.resources.linux.mtr.LinuxMtr method) +
+ + +
(nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ + +
(nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink method) +
+ + +
(nepi.resources.linux.ping.LinuxPing method) +
+ + +
(nepi.resources.linux.route.LinuxRoute method) +
+ + +
(nepi.resources.linux.tap.LinuxTap method) +
+ + +
(nepi.resources.linux.traceroute.LinuxTraceroute method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptest.LinuxUdpTest method) +
+ + +
(nepi.resources.netns.netnsapplication.NetNSApplication method) +
+ + +
(nepi.resources.netns.netnsbase.NetNSBase method) +
+ + +
(nepi.resources.ns3.ns3application.NS3BaseApplication method) +
+ + +
(nepi.resources.ns3.ns3base.NS3Base method) +
+ + +
(nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication method) +
+ + +
(nepi.resources.omf.application.OMFApplication method) +
+ + +
(nepi.resources.planetlab.vroute.PlanetlabVroute method) +
+ +
+ +
do_stop() (nepi.execution.resource.ResourceManager method) +
+ +
+ +
(nepi.resources.linux.application.LinuxApplication method) +
+ + +
(nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
+ + +
(nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
+ + +
(nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ + +
(nepi.resources.linux.route.LinuxRoute method) +
+ + +
(nepi.resources.linux.tap.LinuxTap method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.netns.netnsbase.NetNSBase method) +
+ + +
(nepi.resources.ns3.ns3application.NS3BaseApplication method) +
+ + +
(nepi.resources.ns3.ns3base.NS3Base method) +
+ + +
(nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication method) +
+ + +
(nepi.resources.omf.application.OMFApplication method) +
+ + +
(nepi.resources.planetlab.vroute.PlanetlabVroute method) +
+ +
+ +
DONE (nepi.execution.scheduler.TaskStatus attribute) +
+ + +
DOT (nepi.util.plotter.PFormats attribute) +
+ + +
Double (nepi.execution.attribute.Types attribute) +
+ + +
download() (nepi.resources.linux.node.LinuxNode method) +
+ + +
dump_content_history() (in module nepi.data.processing.ccn.parser) +
+ + +
dump_create() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
dump_factory() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
dump_get() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
dump_header() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
dump_invoke() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
dump_set() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
dump_shutdown() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
dump_start() (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ + +
dump_stop() (nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ + +
dump_to_script() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+
+ +

E

+ + + +
+ +
ec (nepi.execution.ec.FailureManager attribute) +
+ +
+ +
(nepi.execution.resource.ResourceManager attribute) +
+ +
+ +
EC_FAILURE (nepi.execution.ec.FailureLevel attribute) +
+ + +
ECPlotter (class in nepi.util.plotter) +
+ + +
ECSerializer (class in nepi.util.serializer) +
+ + +
ECState (class in nepi.execution.ec) +
+ + +
ecstate (nepi.execution.ec.ExperimentController attribute) +
+ + +
ECXMLParser (class in nepi.util.parsers.xml_parser) +
+ + +
edge_annotation() (nepi.util.netgraph.NetGraph method) +
+ + +
edge_annotations() (nepi.util.netgraph.NetGraph method) +
+ + +
edge_net_annotation() (nepi.util.netgraph.NetGraph method) +
+ + +
edges() (nepi.util.netgraph.NetGraph method) +
+ + +
eintr_retry() (in module nepi.util.sshfuncs) +
+ + +
empty() (nepi.util.parallel.ParallelRun method) +
+ + +
emu_get() (nepi.resources.netns.netnsemulation.NetNSEmulation method) +
+ + +
emu_set() (nepi.resources.netns.netnsemulation.NetNSEmulation method) +
+ + +
emulation (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient attribute) +
+ +
+ +
(nepi.resources.netns.netnsapplication.NetNSApplication attribute) +
+ + +
(nepi.resources.netns.netnsipv4address.NetNSIPv4Address attribute) +
+ + +
(nepi.resources.netns.netnsnode.NetNSNode attribute) +
+ + +
(nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface attribute) +
+ + +
(nepi.resources.netns.netnsroute.NetNSIPv4Route attribute) +
+ + +
(nepi.resources.netns.netnsswitch.NetNSSwitch attribute) +
+ +
+ +
enable_dce (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
enable_trace() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ +
+ +
enabled (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger attribute) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger attribute) +
+ +
+ +
endpoint1 (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
+ +
+ +
(nepi.resources.linux.tunnel.LinuxTunnel attribute) +
+ +
+ +
endpoint2 (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
+ +
+ +
(nepi.resources.linux.tunnel.LinuxTunnel attribute) +
+ +
+ +
endpoint_mkdir() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ +
+ +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ +
+ +
endpoint_node() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
enroll_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
+ +
+ +
enroll_host() (nepi.resources.omf.omf5_api.OMF5API method) +
+ + +
enroll_topic() (nepi.resources.omf.omf6_api.OMF6API method) +
+ + +
Enumerate (nepi.execution.attribute.Types attribute) +
+ + +
ERROR (nepi.execution.scheduler.TaskStatus attribute) +
+ +
+ +
(nepi.resources.linux.node.ExitCode attribute) +
+ +
+ +
error() (nepi.util.logger.Logger method) +
+ + +
establish() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
establish_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
+ +
+ +
(nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
+ +
+ +
establish_udp_connection() (nepi.resources.linux.tap.LinuxTap method) +
+ +
+ +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ +
+ +
eval_failure() (nepi.execution.ec.FailureManager method) +
+ + +
evaluate_normal_convergence() (nepi.execution.runner.ExperimentRunner method) +
+ + +
execute() (in module nepi.util.environ) +
+ +
+ +
(nepi.resources.linux.node.LinuxNode method) +
+ + +
(nepi.resources.omf.omf5_api.OMF5API method) +
+ + +
(nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ +
+ +
execute_command() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
execute_deploy_command() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
execute_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
+ + +
exit() (nepi.resources.omf.omf5_api.OMF5API method) +
+ + +
exit_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
+ + +
ExitCode (class in nepi.resources.linux.node) +
+ + +
exitcode() (nepi.resources.linux.node.LinuxNode method) +
+ + +
exp_dir (nepi.execution.ec.ExperimentController attribute) +
+ +
+ +
(nepi.resources.linux.node.LinuxNode attribute) +
+ +
+ +
exp_home (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
exp_id (nepi.execution.ec.ExperimentController attribute) +
+ +
+ +
(nepi.resources.omf.application.OMFApplication attribute) +
+ + +
(nepi.resources.omf.channel.OMFChannel attribute) +
+ + +
(nepi.resources.omf.interface.OMFWifiInterface attribute) +
+ + +
(nepi.resources.omf.node.OMFNode attribute) +
+ +
+ +
ExperimentController (class in nepi.execution.ec) +
+ + +
ExperimentRunner (class in nepi.execution.runner) +
+ +
+ +

F

+ + + +
+ +
FACTORY (nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
+ + +
factory() (nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ +
+ +
(nepi.resources.ns3.ns3client.NS3Client method) +
+ + +
(nepi.resources.ns3.ns3simulation.NS3Simulation method) +
+ + +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ +
+ +
fail() (nepi.execution.resource.ResourceManager method) +
+ + +
fail_discovery() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ +
+ +
(nepi.resources.planetlab.node.PlanetlabNode method) +
+ + +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
+ +
+ +
fail_node_not_alive() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ +
+ +
(nepi.resources.planetlab.node.PlanetlabNode method) +
+ + +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
+ +
+ +
fail_node_not_available() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ +
+ +
(nepi.resources.planetlab.node.PlanetlabNode method) +
+ + +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
+ +
+ +
fail_not_enough_nodes() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ +
+ +
(nepi.resources.planetlab.node.PlanetlabNode method) +
+ + +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
+ +
+ +
fail_plapi() (nepi.resources.planetlab.node.PlanetlabNode method) +
+ + +
fail_sfaapi() (nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ +
+ +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
+ +
+ +
FAILED (nepi.execution.ec.ECState attribute) +
+ +
+ +
(nepi.execution.resource.ResourceState attribute) +
+ +
+ +
failed_time (nepi.execution.resource.ResourceManager attribute) +
+ + +
failtrap() (in module nepi.execution.resource) +
+ + +
failure_level (nepi.execution.ec.ExperimentController attribute) +
+ + +
FailureLevel (class in nepi.execution.ec) +
+ + +
FailureManager (class in nepi.execution.ec) +
+ + +
fdnetdevice (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
+ +
+ +
(nepi.resources.planetlab.ns3.tuntapfdlink.PlanetlabTunTapFdLink attribute) +
+ +
+ +
fdnode (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
+ + +
FEDORA (nepi.resources.linux.node.OSType attribute) +
+ + +
FEDORA_12 (nepi.resources.linux.node.OSType attribute) +
+ + +
FEDORA_14 (nepi.resources.linux.node.OSType attribute) +
+ + +
FEDORA_8 (nepi.resources.linux.node.OSType attribute) +
+ + +
FIGURE (nepi.util.plotter.PFormats attribute) +
+ + +
FILENOTFOUND (nepi.resources.linux.node.ExitCode attribute) +
+ + +
Filter (nepi.execution.attribute.Flags attribute) +
+ +
+ +
filter_existing_files() (nepi.resources.linux.node.LinuxNode method) +
+ + +
filter_resources() (nepi.execution.ec.ExperimentController method) +
+ + +
find_boxes() (in module nepi.util.rmatcher) +
+ + +
find_home() (nepi.resources.linux.node.LinuxNode method) +
+ + +
find_types() (in module nepi.execution.resource) +
+ + +
finish_multicall() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
FINISHED (nepi.util.sshfuncs.ProcStatus attribute) +
+ + +
Flags (class in nepi.execution.attribute) +
+ + +
flags (nepi.execution.attribute.Attribute attribute) +
+ + +
FLUSH (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
+ +
+ +
(nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
+ +
+ +
flush() (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
+ +
+ +
(nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ + +
(nepi.resources.netns.netnsclient.NetNSClient method) +
+ + +
(nepi.resources.netns.netnsemulation.NetNSEmulation method) +
+ + +
(nepi.resources.ns3.ns3client.NS3Client method) +
+ + +
(nepi.resources.ns3.ns3simulation.NS3Simulation method) +
+ +
+ +
fm (nepi.execution.ec.ExperimentController attribute) +
+ + +
format_args() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
format_environment() (nepi.resources.linux.node.LinuxNode method) +
+ + +
format_kwargs() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
format_value() (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger method) +
+ +
+ +
frcp_configure() (nepi.resources.omf.omf6_api.OMF6API method) +
+ + +
frcp_create() (nepi.resources.omf.omf6_api.OMF6API method) +
+ + +
frcp_inform() (nepi.resources.omf.omf6_api.OMF6API method) +
+ + +
frcp_release() (nepi.resources.omf.omf6_api.OMF6API method) +
+ + +
frcp_request() (nepi.resources.omf.omf6_api.OMF6API method) +
+ + +
from_type() (in module nepi.util.parsers.xml_parser) +
+ + +
from_xml() (nepi.util.parsers.xml_parser.ECXMLParser method) +
+ +
+ +

G

+ + + +
+ +
generate_topology() (nepi.util.netgraph.NetGraph method) +
+ + +
GET (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
+ +
+ +
(nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
+ +
+ +
get() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ + +
(nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
+ + +
(nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ + +
(nepi.resources.netns.netnsbase.NetNSBase method) +
+ + +
(nepi.resources.netns.netnsclient.NetNSClient method) +
+ + +
(nepi.resources.netns.netnswrapper.NetNSWrapper method) +
+ + +
(nepi.resources.ns3.ns3base.NS3Base method) +
+ + +
(nepi.resources.ns3.ns3client.NS3Client method) +
+ + +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ + +
(nepi.resources.omf.omf_client.OMFClient method) +
+ +
+ +
get_api() (nepi.resources.omf.omf_api_factory.OMFAPIFactory class method) +
+ +
+ +
(nepi.resources.planetlab.plcapi.PLCAPIFactory class method) +
+ + +
(nepi.util.manifoldapi.MANIFOLDAPIFactory class method) +
+ + +
(nepi.util.sfaapi.SFAAPIFactory class method) +
+ +
+ +
get_attribute() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager class method) +
+ +
+ +
get_attributes() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager class method) +
+ +
+ +
get_connected() (nepi.execution.resource.ResourceManager method) +
+ + +
get_discover_time() (nepi.execution.ec.ExperimentController method) +
+ + +
get_endpoints() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
+ +
+ +
(nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
+ + +
(nepi.resources.planetlab.ns3.fdudptunnel.PlanetlabNs3FdUdpTunnel method) +
+ +
+ +
get_failed_time() (nepi.execution.ec.ExperimentController method) +
+ + +
get_frequency() (nepi.resources.omf.channel.OMFChannel method) +
+ + +
get_global() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager class method) +
+ +
+ +
get_help() (nepi.execution.resource.ResourceManager class method) +
+ + +
get_interfaces() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_node_flavour() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_node_info() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_node_tags() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_nodes() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_object() (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ +
+ +
get_options() (in module nepi.resources.netns.netnsserver) +
+ +
+ +
(in module nepi.resources.ns3.ns3server) +
+ +
+ +
get_os() (nepi.resources.linux.node.LinuxNode method) +
+ + +
get_p2p_info() (nepi.util.netgraph.NetGraph method) +
+ + +
get_platform() (nepi.execution.resource.ResourceManager class method) +
+ + +
get_provision_time() (nepi.execution.ec.ExperimentController method) +
+ + +
get_ready_time() (nepi.execution.ec.ExperimentController method) +
+ + +
get_release_time() (nepi.execution.ec.ExperimentController method) +
+ + +
get_resource() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
get_resource_info() (nepi.util.manifoldapi.MANIFOLDAPI method) +
+ + +
get_resource_type() (nepi.execution.resource.ResourceFactory class method) +
+ + +
get_resource_urn() (nepi.util.manifoldapi.MANIFOLDAPI method) +
+ + +
get_resources_by_type() (nepi.execution.ec.ExperimentController method) +
+ + +
get_resources_hrn() (nepi.util.sfaapi.SFAAPI method) +
+ + +
get_resources_info() (nepi.util.sfaapi.SFAAPI method) +
+ + +
get_rtype() (nepi.execution.resource.ResourceManager class method) +
+ + +
get_session_key() (nepi.util.manifoldapi.MANIFOLDAPI method) +
+ + +
get_slice_id() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_slice_nodes() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_slice_resources() (nepi.util.manifoldapi.MANIFOLDAPI method) +
+ +
+ +
(nepi.util.sfaapi.SFAAPI method) +
+ +
+ +
get_slice_tags() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_slice_vnet_sys_tag() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_slices() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
get_start_time() (nepi.execution.ec.ExperimentController method) +
+ + +
get_stop_time() (nepi.execution.ec.ExperimentController method) +
+ + +
get_task() (nepi.execution.ec.ExperimentController method) +
+ + +
get_traces() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager class method) +
+ +
+ +
get_value() (nepi.execution.attribute.Attribute method) +
+ + +
gethostbyname() (in module nepi.util.sshfuncs) +
+ + +
getpid() (nepi.resources.linux.node.LinuxNode method) +
+ + +
Global (nepi.execution.attribute.Flags attribute) +
+ + +
gre_connect() (nepi.resources.linux.tap.LinuxTap method) +
+ +
+ +
(nepi.resources.planetlab.tap.PlanetlabTap method) +
+ +
+ +
gre_enabled (nepi.resources.linux.tap.LinuxTap attribute) +
+ + +
guid (nepi.execution.resource.ResourceManager attribute) +
+ + +
GuidGenerator (class in nepi.util.guid) +
+ +
+ +

H

+ + + +
+ +
handle() (nepi.resources.omf.omf6_parser.OMF6Parser method) +
+ + +
handle_message() (in module nepi.resources.netns.netnsserver) +
+ +
+ +
(in module nepi.resources.ns3.ns3server) +
+ +
+ +
handle_omf_message() (nepi.resources.omf.omf_client.OMFClient method) +
+ + +
has_attribute() (nepi.execution.resource.ResourceManager method) +
+ + +
has_changed (nepi.execution.attribute.Attribute attribute) +
+ +
+ +
has_changed() (nepi.execution.resource.ResourceManager method) +
+ + +
has_flag() (nepi.execution.attribute.Attribute method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ +
+ +
HeapScheduler (class in nepi.execution.scheduler) +
+ + +
help (nepi.execution.attribute.Attribute attribute) +
+ +
+ +
(nepi.execution.trace.Trace attribute) +
+ +
+ +
home_dir (nepi.resources.linux.node.LinuxNode attribute) +
+ +
+ +

I

+ + + +
+ +
IFF_TAP (nepi.resources.linux.tap.LinuxTap attribute) +
+ + +
IFF_TUN (nepi.resources.linux.tap.LinuxTap attribute) +
+ + +
in_foreground (nepi.resources.linux.application.LinuxApplication attribute) +
+ + +
info() (nepi.util.logger.Logger method) +
+ + +
inform_failure() (nepi.execution.ec.ExperimentController method) +
+ + +
init_mailbox() (nepi.resources.omf.omf6_parser.OMF6Parser method) +
+ + +
initialize_workers() (nepi.util.parallel.ParallelRun method) +
+ + +
initiate() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
initiate_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
+ +
+ +
(nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
+ +
+ +
initiate_udp_connection() (nepi.resources.linux.tap.LinuxTap method) +
+ +
+ +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ +
+ +
install() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
install_dependencies() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
install_packages() (nepi.resources.linux.node.LinuxNode method) +
+ + +
install_packages_command() (in module nepi.resources.linux.debfuncs) +
+ +
+ +
(in module nepi.resources.linux.rpmfuncs) +
+ + +
(nepi.resources.linux.node.LinuxNode method) +
+ +
+ +
install_rpmfusion_command() (in module nepi.resources.linux.rpmfuncs) +
+ +
+ +
Integer (nepi.execution.attribute.Types attribute) +
+ + +
interface (nepi.resources.netns.netnsipv4address.NetNSIPv4Address attribute) +
+ +
+ +
(nepi.resources.netns.netnsswitch.NetNSSwitch attribute) +
+ +
+ +
INVOKE (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
+ +
+ +
(nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
+ +
+ +
invoke() (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
+ +
+ +
(nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ + +
(nepi.resources.netns.netnsclient.NetNSClient method) +
+ + +
(nepi.resources.netns.netnsemulation.NetNSEmulation method) +
+ + +
(nepi.resources.netns.netnswrapper.NetNSWrapper method) +
+ + +
(nepi.resources.ns3.ns3client.NS3Client method) +
+ + +
(nepi.resources.ns3.ns3simulation.NS3Simulation method) +
+ + +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ +
+ +
ipv4 (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
+ + +
is_alive() (nepi.resources.linux.node.LinuxNode method) +
+ + +
is_control() (in module nepi.data.processing.ccn.parser) +
+ + +
is_finished (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
+ + +
is_rm_instance() (nepi.execution.resource.ResourceManager method) +
+ + +
is_running (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
+ + +
is_source() (nepi.util.netgraph.NetGraph method) +
+ + +
is_started (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
+ + +
is_target() (nepi.util.netgraph.NetGraph method) +
+ + +
is_valid_value() (nepi.execution.attribute.Attribute method) +
+ +
+ +

J

+ + +
+ +
join() (nepi.util.parallel.ParallelRun method) +
+ +
+ +

K

+ + +
+ +
kill() (nepi.resources.linux.node.LinuxNode method) +
+ +
+ +

L

+ + + +
+ +
LADDER (nepi.util.netgraph.TopologyType attribute) +
+ + +
lcopy() (in module nepi.util.execfuncs) +
+ + +
lexec() (in module nepi.util.execfuncs) +
+ + +
lgetpid() (in module nepi.util.execfuncs) +
+ + +
lib_dir (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
LINEAR (nepi.util.netgraph.TopologyType attribute) +
+ + +
LinuxApplication (class in nepi.resources.linux.application) +
+ + +
LinuxCCNApplication (class in nepi.resources.linux.ccn.ccnapplication) +
+ + +
LinuxCCNCat (class in nepi.resources.linux.ccn.ccncat) +
+ + +
LinuxCCNContent (class in nepi.resources.linux.ccn.ccncontent) +
+ + +
LinuxCCND (class in nepi.resources.linux.ccn.ccnd) +
+ + +
LinuxCCNPeek (class in nepi.resources.linux.ccn.ccnpeek) +
+ + +
LinuxCCNPing (class in nepi.resources.linux.ccn.ccnping) +
+ + +
LinuxCCNPingServer (class in nepi.resources.linux.ccn.ccnpingserver) +
+ + +
LinuxCCNPoke (class in nepi.resources.linux.ccn.ccnpoke) +
+ + +
LinuxCCNR (class in nepi.resources.linux.ccn.ccnr) +
+ + +
LinuxChannel (class in nepi.resources.linux.channel) +
+ + +
LinuxDcePing (class in nepi.resources.linux.ns3.ns3pingdceapplication) +
+ + +
LinuxFIBEntry (class in nepi.resources.linux.ccn.fibentry) +
+ + +
LinuxGRETunnel (class in nepi.resources.linux.gretunnel) +
+ + +
LinuxInterface (class in nepi.resources.linux.interface) +
+ + +
LinuxMtr (class in nepi.resources.linux.mtr) +
+ + +
LinuxNetNSClient (class in nepi.resources.linux.netns.netnsclient) +
+ + +
LinuxNetNSEmulation (class in nepi.resources.linux.netns.netnsemulation) +
+ + +
LinuxNode (class in nepi.resources.linux.node) +
+ + +
LinuxNPing (class in nepi.resources.linux.nping) +
+ + +
LinuxNS3CCNDceApplication (class in nepi.resources.linux.ns3.ccn.ns3ccndceapplication) +
+ + +
LinuxNS3Client (class in nepi.resources.linux.ns3.ns3client) +
+ + +
LinuxNS3DceApplication (class in nepi.resources.linux.ns3.ns3dceapplication) +
+ + +
LinuxNS3DceCCNCat (class in nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication) +
+ + +
LinuxNS3DceCCND (class in nepi.resources.linux.ns3.ccn.ns3ccnddceapplication) +
+ + +
LinuxNS3DceCCNPeek (class in nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication) +
+ +
+ +
LinuxNS3DceCCNPoke (class in nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication) +
+ + +
LinuxNS3DceCCNR (class in nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication) +
+ + +
LinuxNS3DceFIBEntry (class in nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication) +
+ + +
LinuxNs3FdUdpTunnel (class in nepi.resources.linux.ns3.fdudptunnel) +
+ + +
LinuxNS3Simulation (class in nepi.resources.linux.ns3.ns3simulation) +
+ + +
LinuxPing (class in nepi.resources.linux.ping) +
+ + +
LinuxRoute (class in nepi.resources.linux.route) +
+ + +
LinuxTap (class in nepi.resources.linux.tap) +
+ + +
LinuxTcpdump (class in nepi.resources.linux.tcpdump) +
+ + +
LinuxTraceroute (class in nepi.resources.linux.traceroute) +
+ + +
LinuxTun (class in nepi.resources.linux.tun) +
+ + +
LinuxTunnel (class in nepi.resources.linux.tunnel) +
+ + +
LinuxTunTapFdLink (class in nepi.resources.linux.ns3.tuntapfdlink) +
+ + +
LinuxUdpTest (class in nepi.resources.linux.udptest) +
+ + +
LinuxUdpTunnel (class in nepi.resources.linux.udptunnel) +
+ + +
lkill() (in module nepi.util.execfuncs) +
+ + +
load() (nepi.execution.ec.ExperimentController class method) +
+ +
+ +
(nepi.util.serializer.ECSerializer method) +
+ +
+ +
load_configuration() (nepi.resources.linux.interface.LinuxInterface method) +
+ + +
load_content_history() (in module nepi.data.processing.ccn.parser) +
+ + +
load_ns3_libraries() (in module nepi.resources.ns3.ns3wrapper) +
+ + +
load_ns3_module() (in module nepi.resources.ns3.ns3wrapper) +
+ + +
local_dir (nepi.execution.ec.ExperimentController attribute) +
+ + +
localhost (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
lock (nepi.resources.omf.omf_api_factory.OMFAPIFactory attribute) +
+ +
+ +
(nepi.resources.planetlab.node.PlanetlabNode attribute) +
+ +
+ +
log() (in module nepi.util.sshfuncs) +
+ +
+ +
(nepi.util.logger.Logger method) +
+ +
+ +
log_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
+ + +
log_message() (nepi.execution.resource.ResourceManager method) +
+ +
+ +
(nepi.resources.linux.application.LinuxApplication method) +
+ + +
(nepi.resources.linux.channel.LinuxChannel method) +
+ + +
(nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
+ + +
(nepi.resources.linux.interface.LinuxInterface method) +
+ + +
(nepi.resources.linux.node.LinuxNode method) +
+ + +
(nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
+ + +
(nepi.util.logger.Logger method) +
+ +
+ +
Logger (class in nepi.util.logger) +
+ + +
logger (nepi.execution.ec.ExperimentController attribute) +
+ +
+ +
(nepi.resources.netns.netnswrapper.NetNSWrapper attribute) +
+ + +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
+ + +
(nepi.util.logger.Logger attribute) +
+ +
+ +
lspawn() (in module nepi.util.execfuncs) +
+ + +
lstatus() (in module nepi.util.execfuncs) +
+ +
+ +

M

+ + + +
+ +
make_control_path() (in module nepi.util.sshfuncs) +
+ + +
make_dict_rec() (nepi.util.sfarspec_proc.SfaRSpecProcessing method) +
+ + +
make_key() (nepi.util.manifoldapi.MANIFOLDAPIFactory class method) +
+ +
+ +
(nepi.util.sfaapi.SFAAPIFactory class method) +
+ +
+ +
make_server_key_args() (in module nepi.util.sshfuncs) +
+ + +
make_uuid() (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ +
+ +
MANIFOLDAPI (class in nepi.util.manifoldapi) +
+ + +
MANIFOLDAPIFactory (class in nepi.util.manifoldapi) +
+ +
+ +
match_tags() (in module nepi.util.rmatcher) +
+ + +
mcapi (nepi.resources.planetlab.plcapi.PLCAPI attribute) +
+ + +
MESH (nepi.util.netgraph.TopologyType attribute) +
+ + +
MessageHandler (class in nepi.resources.omf.messages_5_4) +
+ +
+ +
(class in nepi.resources.omf.messages_6) +
+ +
+ +
mkdir() (nepi.resources.linux.node.LinuxNode method) +
+ + +
mobility (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
+ +
+ +

N

+ + + +
+ +
name (nepi.execution.attribute.Attribute attribute) +
+ +
+ +
(nepi.execution.trace.Trace attribute) +
+ +
+ +
nepi (module) +
+ + +
nepi.data (module) +
+ + +
nepi.data.processing (module) +
+ + +
nepi.data.processing.ccn (module) +
+ + +
nepi.data.processing.ccn.parser (module) +
+ + +
nepi.data.processing.ping (module) +
+ + +
nepi.data.processing.ping.parser (module) +
+ + +
nepi.execution (module) +
+ + +
nepi.execution.attribute (module) +
+ + +
nepi.execution.ec (module) +
+ + +
nepi.execution.resource (module) +
+ + +
nepi.execution.runner (module) +
+ + +
nepi.execution.scheduler (module) +
+ + +
nepi.execution.tags (module) +
+ + +
nepi.execution.trace (module) +
+ + +
nepi.resources (module) +
+ + +
nepi.resources.all (module) +
+ + +
nepi.resources.all.collector (module) +
+ + +
nepi.resources.linux (module) +
+ + +
nepi.resources.linux.application (module) +
+ + +
nepi.resources.linux.ccn (module) +
+ + +
nepi.resources.linux.ccn.ccnapplication (module) +
+ + +
nepi.resources.linux.ccn.ccncat (module) +
+ + +
nepi.resources.linux.ccn.ccncontent (module) +
+ + +
nepi.resources.linux.ccn.ccnd (module) +
+ + +
nepi.resources.linux.ccn.ccnpeek (module) +
+ + +
nepi.resources.linux.ccn.ccnping (module) +
+ + +
nepi.resources.linux.ccn.ccnpingserver (module) +
+ + +
nepi.resources.linux.ccn.ccnpoke (module) +
+ + +
nepi.resources.linux.ccn.ccnr (module) +
+ + +
nepi.resources.linux.ccn.fibentry (module) +
+ + +
nepi.resources.linux.channel (module) +
+ + +
nepi.resources.linux.debfuncs (module) +
+ + +
nepi.resources.linux.gretunnel (module) +
+ + +
nepi.resources.linux.interface (module) +
+ + +
nepi.resources.linux.mtr (module) +
+ + +
nepi.resources.linux.netns (module) +
+ + +
nepi.resources.linux.netns.netnsclient (module) +
+ + +
nepi.resources.linux.netns.netnsemulation (module) +
+ + +
nepi.resources.linux.node (module) +
+ + +
nepi.resources.linux.nping (module) +
+ + +
nepi.resources.linux.ns3 (module) +
+ + +
nepi.resources.linux.ns3.ccn (module) +
+ + +
nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication (module) +
+ + +
nepi.resources.linux.ns3.ccn.ns3ccndceapplication (module) +
+ + +
nepi.resources.linux.ns3.ccn.ns3ccnddceapplication (module) +
+ + +
nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication (module) +
+ + +
nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication (module) +
+ + +
nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication (module) +
+ + +
nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication (module) +
+ + +
nepi.resources.linux.ns3.fdudptunnel (module) +
+ + +
nepi.resources.linux.ns3.ns3client (module) +
+ + +
nepi.resources.linux.ns3.ns3dceapplication (module) +
+ + +
nepi.resources.linux.ns3.ns3pingdceapplication (module) +
+ + +
nepi.resources.linux.ns3.ns3simulation (module) +
+ + +
nepi.resources.linux.ns3.tuntapfdlink (module) +
+ + +
nepi.resources.linux.ping (module) +
+ + +
nepi.resources.linux.route (module) +
+ + +
nepi.resources.linux.rpmfuncs (module) +
+ + +
nepi.resources.linux.tap (module) +
+ + +
nepi.resources.linux.tcpdump (module) +
+ + +
nepi.resources.linux.traceroute (module) +
+ + +
nepi.resources.linux.tun (module) +
+ + +
nepi.resources.linux.tunnel (module) +
+ + +
nepi.resources.linux.udptest (module) +
+ + +
nepi.resources.linux.udptunnel (module) +
+ + +
nepi.resources.netns (module) +
+ + +
nepi.resources.netns.netnsapplication (module) +
+ + +
nepi.resources.netns.netnsbase (module) +
+ + +
nepi.resources.netns.netnsclient (module) +
+ + +
nepi.resources.netns.netnsemulation (module) +
+ + +
nepi.resources.netns.netnsinterface (module) +
+ + +
nepi.resources.netns.netnsipv4address (module) +
+ + +
nepi.resources.netns.netnsnode (module) +
+ + +
nepi.resources.netns.netnsnodeinterface (module) +
+ + +
nepi.resources.netns.netnsroute (module) +
+ + +
nepi.resources.netns.netnsserver (module) +
+ + +
nepi.resources.netns.netnsswitch (module) +
+ + +
nepi.resources.netns.netnswrapper (module) +
+ + +
nepi.resources.netns.netnswrapper_debug (module) +
+ + +
nepi.resources.ns3 (module) +
+ + +
nepi.resources.ns3.classes (module) +
+ + +
nepi.resources.ns3.classes.aarf_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.aarfcd_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.adhoc_wifi_mac (module) +
+ + +
nepi.resources.ns3.classes.aloha_noack_net_device (module) +
+ + +
nepi.resources.ns3.classes.amrr_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.ap_wifi_mac (module) +
+ + +
nepi.resources.ns3.classes.arf_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.arp_l3protocol (module) +
+ + +
nepi.resources.ns3.classes.base_station_net_device (module) +
+ + +
nepi.resources.ns3.classes.binary_error_model (module) +
+ + +
nepi.resources.ns3.classes.binary_error_sixlow_model (module) +
+ + +
nepi.resources.ns3.classes.bridge_channel (module) +
+ + +
nepi.resources.ns3.classes.bridge_net_device (module) +
+ + +
nepi.resources.ns3.classes.bulk_send_application (module) +
+ + +
nepi.resources.ns3.classes.burst_error_model (module) +
+ + +
nepi.resources.ns3.classes.cara_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.constant_acceleration_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.constant_position_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.constant_rate_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.constant_speed_propagation_delay_model (module) +
+ + +
nepi.resources.ns3.classes.constant_velocity_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.cost231propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.csma_channel (module) +
+ + +
nepi.resources.ns3.classes.csma_net_device (module) +
+ + +
nepi.resources.ns3.classes.drop_tail_queue (module) +
+ + +
nepi.resources.ns3.classes.dsrdsr_routing (module) +
+ + +
nepi.resources.ns3.classes.emu_net_device (module) +
+ + +
nepi.resources.ns3.classes.error_channel (module) +
+ + +
nepi.resources.ns3.classes.error_channel_sixlow (module) +
+ + +
nepi.resources.ns3.classes.error_net_device (module) +
+ + +
nepi.resources.ns3.classes.fd_net_device (module) +
+ + +
nepi.resources.ns3.classes.fixed_rss_loss_model (module) +
+ + +
nepi.resources.ns3.classes.friis_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.gauss_markov_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.hierarchical_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.icmpv4l4protocol (module) +
+ + +
nepi.resources.ns3.classes.icmpv6l4protocol (module) +
+ + +
nepi.resources.ns3.classes.ideal_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.ipv4l3protocol (module) +
+ + +
nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.jakes_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.list_error_model (module) +
+ + +
nepi.resources.ns3.classes.log_distance_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.loopback_net_device (module) +
+ + +
nepi.resources.ns3.classes.lr_wpan_net_device (module) +
+ + +
nepi.resources.ns3.classes.lte_enb_net_device (module) +
+ + +
nepi.resources.ns3.classes.lte_simple_net_device (module) +
+ + +
nepi.resources.ns3.classes.lte_ue_net_device (module) +
+ + +
nepi.resources.ns3.classes.matrix_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.mesh_point_device (module) +
+ + +
nepi.resources.ns3.classes.mesh_wifi_interface_mac (module) +
+ + +
nepi.resources.ns3.classes.minstrel_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.multi_model_spectrum_channel (module) +
+ + +
nepi.resources.ns3.classes.nakagami_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.nist_error_rate_model (module) +
+ + +
nepi.resources.ns3.classes.node (module) +
+ + +
nepi.resources.ns3.classes.non_communicating_net_device (module) +
+ + +
nepi.resources.ns3.classes.ocb_wifi_mac (module) +
+ + +
nepi.resources.ns3.classes.oh_buildings_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.okumura_hata_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.on_off_application (module) +
+ + +
nepi.resources.ns3.classes.onoe_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.packet_sink (module) +
+ + +
nepi.resources.ns3.classes.ping6 (module) +
+ + +
nepi.resources.ns3.classes.point_to_point_channel (module) +
+ + +
nepi.resources.ns3.classes.point_to_point_net_device (module) +
+ + +
nepi.resources.ns3.classes.point_to_point_remote_channel (module) +
+ + +
nepi.resources.ns3.classes.radvd (module) +
+ + +
nepi.resources.ns3.classes.random_direction2d_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.random_propagation_delay_model (module) +
+ + +
nepi.resources.ns3.classes.random_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.random_walk2d_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.random_waypoint_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.range_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.rate_error_model (module) +
+ + +
nepi.resources.ns3.classes.receive_list_error_model (module) +
+ + +
nepi.resources.ns3.classes.red_queue (module) +
+ + +
nepi.resources.ns3.classes.rraa_wifi_manager (module) +
+ + +
nepi.resources.ns3.classes.simple_channel (module) +
+ + +
nepi.resources.ns3.classes.simple_net_device (module) +
+ + +
nepi.resources.ns3.classes.single_model_spectrum_channel (module) +
+ + +
nepi.resources.ns3.classes.six_low_pan_net_device (module) +
+ + +
nepi.resources.ns3.classes.sta_wifi_mac (module) +
+ + +
nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.subscriber_station_net_device (module) +
+ + +
nepi.resources.ns3.classes.tap_bridge (module) +
+ + +
nepi.resources.ns3.classes.tcp_l4protocol (module) +
+ + +
nepi.resources.ns3.classes.three_log_distance_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model (module) +
+ + +
nepi.resources.ns3.classes.uan_channel (module) +
+ + +
nepi.resources.ns3.classes.udp_client (module) +
+ + +
nepi.resources.ns3.classes.udp_echo_client (module) +
+ + +
nepi.resources.ns3.classes.udp_echo_server (module) +
+ + +
nepi.resources.ns3.classes.udp_l4protocol (module) +
+ + +
nepi.resources.ns3.classes.udp_server (module) +
+ + +
nepi.resources.ns3.classes.udp_trace_client (module) +
+ + +
nepi.resources.ns3.classes.v4ping (module) +
+ + +
nepi.resources.ns3.classes.virtual_net_device (module) +
+ + +
nepi.resources.ns3.classes.waypoint_mobility_model (module) +
+ + +
nepi.resources.ns3.classes.wifi_net_device (module) +
+ + +
nepi.resources.ns3.classes.yans_error_rate_model (module) +
+ + +
nepi.resources.ns3.classes.yans_wifi_channel (module) +
+ + +
nepi.resources.ns3.classes.yans_wifi_phy (module) +
+ + +
nepi.resources.ns3.ns3application (module) +
+ + +
nepi.resources.ns3.ns3arpl3protocol (module) +
+ + +
nepi.resources.ns3.ns3base (module) +
+ + +
nepi.resources.ns3.ns3ccndceapplication (module) +
+ + +
nepi.resources.ns3.ns3channel (module) +
+ + +
nepi.resources.ns3.ns3client (module) +
+ + +
nepi.resources.ns3.ns3dceapplication (module) +
+ + +
nepi.resources.ns3.ns3dcehelper (module) +
+ + +
nepi.resources.ns3.ns3errormodel (module) +
+ + +
nepi.resources.ns3.ns3errorratemodel (module) +
+ + +
nepi.resources.ns3.ns3fdnetdevice (module) +
+ + +
nepi.resources.ns3.ns3icmpv4l4protocol (module) +
+ + +
nepi.resources.ns3.ns3ipv4l3protocol (module) +
+ + +
nepi.resources.ns3.ns3mobilitymodel (module) +
+ + +
nepi.resources.ns3.ns3netdevice (module) +
+ + +
nepi.resources.ns3.ns3node (module) +
+ + +
nepi.resources.ns3.ns3pipechanel (module) +
+ + +
nepi.resources.ns3.ns3propagationdelaymodel (module) +
+ + +
nepi.resources.ns3.ns3propagationlossmodel (module) +
+ + +
nepi.resources.ns3.ns3queue (module) +
+ + +
nepi.resources.ns3.ns3route (module) +
+ + +
nepi.resources.ns3.ns3server (module) +
+ + +
nepi.resources.ns3.ns3simulation (module) +
+ + +
nepi.resources.ns3.ns3wifichannel (module) +
+ + +
nepi.resources.ns3.ns3wifimac (module) +
+ + +
nepi.resources.ns3.ns3wifinetdevice (module) +
+ + +
nepi.resources.ns3.ns3wifiphy (module) +
+ + +
nepi.resources.ns3.ns3wifiremotestationmanager (module) +
+ + +
nepi.resources.ns3.ns3wrapper (module) +
+ + +
nepi.resources.ns3.ns3wrapper_debug (module) +
+ + +
nepi.resources.ns3.resource_manager_generator (module) +
+ + +
nepi.resources.omf (module) +
+ + +
nepi.resources.omf.application (module) +
+ +
+ +
nepi.resources.omf.channel (module) +
+ + +
nepi.resources.omf.interface (module) +
+ + +
nepi.resources.omf.messages_5_4 (module) +
+ + +
nepi.resources.omf.messages_6 (module) +
+ + +
nepi.resources.omf.node (module) +
+ + +
nepi.resources.omf.omf5_api (module) +
+ + +
nepi.resources.omf.omf6_api (module) +
+ + +
nepi.resources.omf.omf6_parser (module) +
+ + +
nepi.resources.omf.omf_api_factory (module) +
+ + +
nepi.resources.omf.omf_client (module) +
+ + +
nepi.resources.omf.omf_resource (module) +
+ + +
nepi.resources.omf.wilabt_node (module) +
+ + +
nepi.resources.planetlab (module) +
+ + +
nepi.resources.planetlab.node (module) +
+ + +
nepi.resources.planetlab.ns3 (module) +
+ + +
nepi.resources.planetlab.ns3.fdudptunnel (module) +
+ + +
nepi.resources.planetlab.ns3.tuntapfdlink (module) +
+ + +
nepi.resources.planetlab.openvswitch (module) +
+ + +
nepi.resources.planetlab.openvswitch.ovs (module) +
+ + +
nepi.resources.planetlab.openvswitch.ovsport (module) +
+ + +
nepi.resources.planetlab.plcapi (module) +
+ + +
nepi.resources.planetlab.sfa_node (module) +
+ + +
nepi.resources.planetlab.tap (module) +
+ + +
nepi.resources.planetlab.tun (module) +
+ + +
nepi.resources.planetlab.vroute (module) +
+ + +
nepi.util (module) +
+ + +
nepi.util.environ (module) +
+ + +
nepi.util.execfuncs (module) +
+ + +
nepi.util.guid (module) +
+ + +
nepi.util.logger (module) +
+ + +
nepi.util.manifoldapi (module) +
+ + +
nepi.util.netgraph (module) +
+ + +
nepi.util.parallel (module) +
+ + +
nepi.util.parsers (module) +
+ + +
nepi.util.parsers.xml_parser (module) +
+ + +
nepi.util.plotter (module) +
+ + +
nepi.util.rmatcher (module) +
+ + +
nepi.util.serializer (module) +
+ + +
nepi.util.sfaapi (module) +
+ + +
nepi.util.sfarspec_proc (module) +
+ + +
nepi.util.sshfuncs (module) +
+ + +
nepi.util.statfuncs (module) +
+ + +
nepi.util.timefuncs (module) +
+ + +
nepi_home (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
NetGraph (class in nepi.util.netgraph) +
+ + +
netgraph (nepi.execution.ec.ExperimentController attribute) +
+ + +
netns_repo (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ + +
netns_src (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ + +
netns_version (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ + +
NetNSApplication (class in nepi.resources.netns.netnsapplication) +
+ + +
NetNSBase (class in nepi.resources.netns.netnsbase) +
+ + +
NetNSClient (class in nepi.resources.netns.netnsclient) +
+ + +
NetNSEmulation (class in nepi.resources.netns.netnsemulation) +
+ + +
NetNSInterface (class in nepi.resources.netns.netnsinterface) +
+ + +
NetNSIPv4Address (class in nepi.resources.netns.netnsipv4address) +
+ + +
NetNSIPv4Route (class in nepi.resources.netns.netnsroute) +
+ + +
NetNSNode (class in nepi.resources.netns.netnsnode) +
+ + +
NetNSNodeInterface (class in nepi.resources.netns.netnsnodeinterface) +
+ + +
NetNSSwitch (class in nepi.resources.netns.netnsswitch) +
+ + +
NetNSWrapper (class in nepi.resources.netns.netnswrapper) +
+ + +
NetNSWrapperDebuger (class in nepi.resources.netns.netnswrapper_debug) +
+ + +
NetNSWrapperMessage (class in nepi.resources.netns.netnsserver) +
+ + +
network_types (nepi.resources.planetlab.plcapi.PLCAPI attribute) +
+ + +
NEW (nepi.execution.resource.ResourceState attribute) +
+ +
+ +
(nepi.execution.scheduler.TaskStatus attribute) +
+ +
+ +
newexp_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
+ + +
next() (nepi.execution.scheduler.HeapScheduler method) +
+ +
+ +
(nepi.util.guid.GuidGenerator method) +
+ +
+ +
node (nepi.resources.linux.application.LinuxApplication attribute) +
+ +
+ +
(nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication attribute) +
+ + +
(nepi.resources.linux.ccn.ccncontent.LinuxCCNContent attribute) +
+ + +
(nepi.resources.linux.ccn.ccnr.LinuxCCNR attribute) +
+ + +
(nepi.resources.linux.ccn.fibentry.LinuxFIBEntry attribute) +
+ + +
(nepi.resources.linux.interface.LinuxInterface attribute) +
+ + +
(nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
+ + +
(nepi.resources.linux.route.LinuxRoute attribute) +
+ + +
(nepi.resources.linux.tap.LinuxTap attribute) +
+ + +
(nepi.resources.netns.netnsapplication.NetNSApplication attribute) +
+ + +
(nepi.resources.netns.netnsipv4address.NetNSIPv4Address attribute) +
+ + +
(nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface attribute) +
+ + +
(nepi.resources.netns.netnsroute.NetNSIPv4Route attribute) +
+ + +
(nepi.resources.netns.netnsswitch.NetNSSwitch attribute) +
+ + +
(nepi.resources.ns3.ns3application.NS3BaseApplication attribute) +
+ + +
(nepi.resources.ns3.ns3arpl3protocol.NS3BaseArpL3Protocol attribute) +
+ + +
(nepi.resources.ns3.ns3base.NS3Base attribute) +
+ + +
(nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel attribute) +
+ + +
(nepi.resources.ns3.ns3icmpv4l4protocol.NS3BaseIcmpv4L4Protocol attribute) +
+ + +
(nepi.resources.ns3.ns3ipv4l3protocol.NS3BaseIpv4L3Protocol attribute) +
+ + +
(nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
+ + +
(nepi.resources.ns3.ns3pipechanel.NS3BasePipeChannel attribute) +
+ + +
(nepi.resources.ns3.ns3queue.NS3BaseQueue attribute) +
+ + +
(nepi.resources.ns3.ns3route.NS3Route attribute) +
+ + +
(nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac attribute) +
+ + +
(nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy attribute) +
+ + +
(nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager attribute) +
+ + +
(nepi.resources.omf.application.OMFApplication attribute) +
+ + +
(nepi.resources.omf.interface.OMFWifiInterface attribute) +
+ + +
(nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch attribute) +
+ + +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort attribute) +
+ + +
(nepi.resources.planetlab.tap.PlanetlabTap attribute) +
+ + +
(nepi.resources.planetlab.vroute.PlanetlabVroute attribute) +
+ +
+ +
node1 (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
+ + +
node2 (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
+ + +
node_annotation() (nepi.util.netgraph.NetGraph method) +
+ + +
node_annotations() (nepi.util.netgraph.NetGraph method) +
+ + +
node_home (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
node_id (nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
+ + +
node_ip_annotations() (nepi.util.netgraph.NetGraph method) +
+ + +
nodes() (nepi.resources.omf.omf_client.OMFClient method) +
+ +
+ +
(nepi.util.netgraph.NetGraph method) +
+ +
+ +
noop_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
+ + +
NoRead (nepi.execution.attribute.Flags attribute) +
+ + +
NOT_STARTED (nepi.util.sshfuncs.ProcStatus attribute) +
+ + +
NoWrite (nepi.execution.attribute.Flags attribute) +
+ + +
ns3 (nepi.resources.ns3.ns3wrapper.NS3Wrapper attribute) +
+ + +
ns3_build_location (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
ns3_get() (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
+ + +
ns3_repo (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
ns3_set() (nepi.resources.ns3.ns3simulation.NS3Simulation method) +
+ + +
ns3_src_location (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
NS3AarfcdWifiManager (class in nepi.resources.ns3.classes.aarfcd_wifi_manager) +
+ + +
NS3AarfWifiManager (class in nepi.resources.ns3.classes.aarf_wifi_manager) +
+ + +
NS3AdhocWifiMac (class in nepi.resources.ns3.classes.adhoc_wifi_mac) +
+ + +
NS3AlohaNoackNetDevice (class in nepi.resources.ns3.classes.aloha_noack_net_device) +
+ + +
NS3AmrrWifiManager (class in nepi.resources.ns3.classes.amrr_wifi_manager) +
+ + +
NS3ApWifiMac (class in nepi.resources.ns3.classes.ap_wifi_mac) +
+ + +
NS3ArfWifiManager (class in nepi.resources.ns3.classes.arf_wifi_manager) +
+ + +
NS3ArpL3Protocol (class in nepi.resources.ns3.classes.arp_l3protocol) +
+ + +
NS3Base (class in nepi.resources.ns3.ns3base) +
+ + +
NS3BaseApplication (class in nepi.resources.ns3.ns3application) +
+ + +
NS3BaseArpL3Protocol (class in nepi.resources.ns3.ns3arpl3protocol) +
+ + +
NS3BaseCCNDceApplication (class in nepi.resources.ns3.ns3ccndceapplication) +
+ + +
NS3BaseChannel (class in nepi.resources.ns3.ns3channel) +
+ + +
NS3BaseDceApplication (class in nepi.resources.ns3.ns3dceapplication) +
+ + +
NS3BaseErrorModel (class in nepi.resources.ns3.ns3errormodel) +
+ + +
NS3BaseErrorRateModel (class in nepi.resources.ns3.ns3errorratemodel) +
+ + +
NS3BaseFdNetDevice (class in nepi.resources.ns3.ns3fdnetdevice) +
+ + +
NS3BaseIcmpv4L4Protocol (class in nepi.resources.ns3.ns3icmpv4l4protocol) +
+ + +
NS3BaseIpv4L3Protocol (class in nepi.resources.ns3.ns3ipv4l3protocol) +
+ + +
NS3BaseMobilityModel (class in nepi.resources.ns3.ns3mobilitymodel) +
+ + +
NS3BaseNetDevice (class in nepi.resources.ns3.ns3netdevice) +
+ + +
NS3BaseNode (class in nepi.resources.ns3.ns3node) +
+ + +
NS3BasePipeChannel (class in nepi.resources.ns3.ns3pipechanel) +
+ + +
NS3BasePropagationDelayModel (class in nepi.resources.ns3.ns3propagationdelaymodel) +
+ + +
NS3BasePropagationLossModel (class in nepi.resources.ns3.ns3propagationlossmodel) +
+ + +
NS3BaseQueue (class in nepi.resources.ns3.ns3queue) +
+ + +
NS3BaseStationNetDevice (class in nepi.resources.ns3.classes.base_station_net_device) +
+ + +
NS3BaseWifiChannel (class in nepi.resources.ns3.ns3wifichannel) +
+ + +
NS3BaseWifiMac (class in nepi.resources.ns3.ns3wifimac) +
+ + +
NS3BaseWifiNetDevice (class in nepi.resources.ns3.ns3wifinetdevice) +
+ + +
NS3BaseWifiPhy (class in nepi.resources.ns3.ns3wifiphy) +
+ + +
NS3BaseWifiRemoteStationManager (class in nepi.resources.ns3.ns3wifiremotestationmanager) +
+ + +
NS3BinaryErrorModel (class in nepi.resources.ns3.classes.binary_error_model) +
+ + +
NS3BinaryErrorSixlowModel (class in nepi.resources.ns3.classes.binary_error_sixlow_model) +
+ + +
NS3BridgeChannel (class in nepi.resources.ns3.classes.bridge_channel) +
+ + +
NS3BridgeNetDevice (class in nepi.resources.ns3.classes.bridge_net_device) +
+ + +
NS3BulkSendApplication (class in nepi.resources.ns3.classes.bulk_send_application) +
+ + +
NS3BurstErrorModel (class in nepi.resources.ns3.classes.burst_error_model) +
+ + +
NS3CaraWifiManager (class in nepi.resources.ns3.classes.cara_wifi_manager) +
+ + +
NS3Client (class in nepi.resources.ns3.ns3client) +
+ + +
NS3ConstantAccelerationMobilityModel (class in nepi.resources.ns3.classes.constant_acceleration_mobility_model) +
+ + +
NS3ConstantPositionMobilityModel (class in nepi.resources.ns3.classes.constant_position_mobility_model) +
+ + +
NS3ConstantRateWifiManager (class in nepi.resources.ns3.classes.constant_rate_wifi_manager) +
+ + +
NS3ConstantSpeedPropagationDelayModel (class in nepi.resources.ns3.classes.constant_speed_propagation_delay_model) +
+ + +
NS3ConstantVelocityMobilityModel (class in nepi.resources.ns3.classes.constant_velocity_mobility_model) +
+ + +
NS3Cost231PropagationLossModel (class in nepi.resources.ns3.classes.cost231propagation_loss_model) +
+ + +
NS3CsmaChannel (class in nepi.resources.ns3.classes.csma_channel) +
+ + +
NS3CsmaNetDevice (class in nepi.resources.ns3.classes.csma_net_device) +
+ + +
NS3DceHelper (class in nepi.resources.ns3.ns3dcehelper) +
+ + +
NS3DropTailQueue (class in nepi.resources.ns3.classes.drop_tail_queue) +
+ + +
NS3dsrDsrRouting (class in nepi.resources.ns3.classes.dsrdsr_routing) +
+ + +
NS3EmuNetDevice (class in nepi.resources.ns3.classes.emu_net_device) +
+ + +
NS3ErrorChannel (class in nepi.resources.ns3.classes.error_channel) +
+ + +
NS3ErrorChannelSixlow (class in nepi.resources.ns3.classes.error_channel_sixlow) +
+ + +
NS3ErrorNetDevice (class in nepi.resources.ns3.classes.error_net_device) +
+ + +
NS3FdNetDevice (class in nepi.resources.ns3.classes.fd_net_device) +
+ + +
NS3FixedRssLossModel (class in nepi.resources.ns3.classes.fixed_rss_loss_model) +
+ + +
NS3FriisPropagationLossModel (class in nepi.resources.ns3.classes.friis_propagation_loss_model) +
+ + +
NS3GaussMarkovMobilityModel (class in nepi.resources.ns3.classes.gauss_markov_mobility_model) +
+ + +
NS3HierarchicalMobilityModel (class in nepi.resources.ns3.classes.hierarchical_mobility_model) +
+ + +
NS3HybridBuildingsPropagationLossModel (class in nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model) +
+ + +
NS3Icmpv4L4Protocol (class in nepi.resources.ns3.classes.icmpv4l4protocol) +
+ + +
NS3Icmpv6L4Protocol (class in nepi.resources.ns3.classes.icmpv6l4protocol) +
+ + +
NS3IdealWifiManager (class in nepi.resources.ns3.classes.ideal_wifi_manager) +
+ + +
NS3Ipv4L3Protocol (class in nepi.resources.ns3.classes.ipv4l3protocol) +
+ + +
NS3ItuR1411LosPropagationLossModel (class in nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model) +
+ + +
NS3ItuR1411NlosOverRooftopPropagationLossModel (class in nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model) +
+ + +
NS3JakesPropagationLossModel (class in nepi.resources.ns3.classes.jakes_propagation_loss_model) +
+ + +
NS3Kun2600MhzPropagationLossModel (class in nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model) +
+ + +
NS3ListErrorModel (class in nepi.resources.ns3.classes.list_error_model) +
+ + +
NS3LogDistancePropagationLossModel (class in nepi.resources.ns3.classes.log_distance_propagation_loss_model) +
+ + +
NS3LoopbackNetDevice (class in nepi.resources.ns3.classes.loopback_net_device) +
+ + +
NS3LrWpanNetDevice (class in nepi.resources.ns3.classes.lr_wpan_net_device) +
+ + +
NS3LteEnbNetDevice (class in nepi.resources.ns3.classes.lte_enb_net_device) +
+ + +
NS3LteSimpleNetDevice (class in nepi.resources.ns3.classes.lte_simple_net_device) +
+ + +
NS3LteUeNetDevice (class in nepi.resources.ns3.classes.lte_ue_net_device) +
+ + +
NS3MatrixPropagationLossModel (class in nepi.resources.ns3.classes.matrix_propagation_loss_model) +
+ + +
NS3MeshPointDevice (class in nepi.resources.ns3.classes.mesh_point_device) +
+ + +
NS3MeshWifiInterfaceMac (class in nepi.resources.ns3.classes.mesh_wifi_interface_mac) +
+ + +
NS3MinstrelWifiManager (class in nepi.resources.ns3.classes.minstrel_wifi_manager) +
+ + +
NS3MultiModelSpectrumChannel (class in nepi.resources.ns3.classes.multi_model_spectrum_channel) +
+ + +
NS3NakagamiPropagationLossModel (class in nepi.resources.ns3.classes.nakagami_propagation_loss_model) +
+ + +
NS3NistErrorRateModel (class in nepi.resources.ns3.classes.nist_error_rate_model) +
+ + +
NS3Node (class in nepi.resources.ns3.classes.node) +
+ + +
NS3NonCommunicatingNetDevice (class in nepi.resources.ns3.classes.non_communicating_net_device) +
+ + +
NS3OcbWifiMac (class in nepi.resources.ns3.classes.ocb_wifi_mac) +
+ + +
NS3OhBuildingsPropagationLossModel (class in nepi.resources.ns3.classes.oh_buildings_propagation_loss_model) +
+ + +
NS3OkumuraHataPropagationLossModel (class in nepi.resources.ns3.classes.okumura_hata_propagation_loss_model) +
+ + +
NS3OnoeWifiManager (class in nepi.resources.ns3.classes.onoe_wifi_manager) +
+ + +
NS3OnOffApplication (class in nepi.resources.ns3.classes.on_off_application) +
+ + +
NS3PacketSink (class in nepi.resources.ns3.classes.packet_sink) +
+ + +
NS3Ping6 (class in nepi.resources.ns3.classes.ping6) +
+ + +
NS3PointToPointChannel (class in nepi.resources.ns3.classes.point_to_point_channel) +
+ + +
NS3PointToPointNetDevice (class in nepi.resources.ns3.classes.point_to_point_net_device) +
+ + +
NS3PointToPointRemoteChannel (class in nepi.resources.ns3.classes.point_to_point_remote_channel) +
+ + +
NS3Radvd (class in nepi.resources.ns3.classes.radvd) +
+ + +
NS3RandomDirection2dMobilityModel (class in nepi.resources.ns3.classes.random_direction2d_mobility_model) +
+ + +
NS3RandomPropagationDelayModel (class in nepi.resources.ns3.classes.random_propagation_delay_model) +
+ + +
NS3RandomPropagationLossModel (class in nepi.resources.ns3.classes.random_propagation_loss_model) +
+ + +
NS3RandomWalk2dMobilityModel (class in nepi.resources.ns3.classes.random_walk2d_mobility_model) +
+ + +
NS3RandomWaypointMobilityModel (class in nepi.resources.ns3.classes.random_waypoint_mobility_model) +
+ + +
NS3RangePropagationLossModel (class in nepi.resources.ns3.classes.range_propagation_loss_model) +
+ + +
NS3RateErrorModel (class in nepi.resources.ns3.classes.rate_error_model) +
+ + +
NS3ReceiveListErrorModel (class in nepi.resources.ns3.classes.receive_list_error_model) +
+ + +
NS3RedQueue (class in nepi.resources.ns3.classes.red_queue) +
+ + +
NS3Route (class in nepi.resources.ns3.ns3route) +
+ + +
NS3RraaWifiManager (class in nepi.resources.ns3.classes.rraa_wifi_manager) +
+ + +
NS3SimpleChannel (class in nepi.resources.ns3.classes.simple_channel) +
+ + +
NS3SimpleNetDevice (class in nepi.resources.ns3.classes.simple_net_device) +
+ + +
NS3Simulation (class in nepi.resources.ns3.ns3simulation) +
+ + +
NS3SingleModelSpectrumChannel (class in nepi.resources.ns3.classes.single_model_spectrum_channel) +
+ + +
NS3SixLowPanNetDevice (class in nepi.resources.ns3.classes.six_low_pan_net_device) +
+ + +
NS3StaWifiMac (class in nepi.resources.ns3.classes.sta_wifi_mac) +
+ + +
NS3SteadyStateRandomWaypointMobilityModel (class in nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model) +
+ + +
NS3SubscriberStationNetDevice (class in nepi.resources.ns3.classes.subscriber_station_net_device) +
+ + +
NS3TapBridge (class in nepi.resources.ns3.classes.tap_bridge) +
+ + +
NS3TcpL4Protocol (class in nepi.resources.ns3.classes.tcp_l4protocol) +
+ + +
NS3ThreeLogDistancePropagationLossModel (class in nepi.resources.ns3.classes.three_log_distance_propagation_loss_model) +
+ + +
NS3TwoRayGroundPropagationLossModel (class in nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model) +
+ + +
NS3UanChannel (class in nepi.resources.ns3.classes.uan_channel) +
+ + +
NS3UdpClient (class in nepi.resources.ns3.classes.udp_client) +
+ + +
NS3UdpEchoClient (class in nepi.resources.ns3.classes.udp_echo_client) +
+ + +
NS3UdpEchoServer (class in nepi.resources.ns3.classes.udp_echo_server) +
+ + +
NS3UdpL4Protocol (class in nepi.resources.ns3.classes.udp_l4protocol) +
+ + +
NS3UdpServer (class in nepi.resources.ns3.classes.udp_server) +
+ + +
NS3UdpTraceClient (class in nepi.resources.ns3.classes.udp_trace_client) +
+ + +
NS3V4Ping (class in nepi.resources.ns3.classes.v4ping) +
+ + +
NS3VirtualNetDevice (class in nepi.resources.ns3.classes.virtual_net_device) +
+ + +
NS3WaypointMobilityModel (class in nepi.resources.ns3.classes.waypoint_mobility_model) +
+ + +
NS3WifiNetDevice (class in nepi.resources.ns3.classes.wifi_net_device) +
+ + +
NS3Wrapper (class in nepi.resources.ns3.ns3wrapper) +
+ + +
NS3WrapperDebuger (class in nepi.resources.ns3.ns3wrapper_debug) +
+ + +
NS3WrapperMessage (class in nepi.resources.ns3.ns3server) +
+ + +
NS3YansErrorRateModel (class in nepi.resources.ns3.classes.yans_error_rate_model) +
+ + +
NS3YansWifiChannel (class in nepi.resources.ns3.classes.yans_wifi_channel) +
+ + +
NS3YansWifiPhy (class in nepi.resources.ns3.classes.yans_wifi_phy) +
+ + +
nthreads (nepi.execution.ec.ExperimentController attribute) +
+ +
+ +

O

+ + + +
+ +
OK (nepi.execution.ec.FailureLevel attribute) +
+ +
+ +
(nepi.resources.linux.node.ExitCode attribute) +
+ +
+ +
OMF5API (class in nepi.resources.omf.omf5_api) +
+ + +
OMF6API (class in nepi.resources.omf.omf6_api) +
+ + +
OMF6Parser (class in nepi.resources.omf.omf6_parser) +
+ + +
OMFAPIFactory (class in nepi.resources.omf.omf_api_factory) +
+ + +
OMFApplication (class in nepi.resources.omf.application) +
+ + +
OMFChannel (class in nepi.resources.omf.channel) +
+ + +
OMFClient (class in nepi.resources.omf.omf_client) +
+ + +
OMFNode (class in nepi.resources.omf.node) +
+ +
+ +
OMFResource (class in nepi.resources.omf.omf_resource) +
+ + +
OMFWifiInterface (class in nepi.resources.omf.interface) +
+ + +
open_socket() (in module nepi.resources.ns3.ns3server) +
+ + +
openssh_has_persist() (in module nepi.util.sshfuncs) +
+ + +
order (nepi.util.netgraph.NetGraph attribute) +
+ + +
os (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
OSType (class in nepi.resources.linux.node) +
+ + +
ovs_status() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
+ + +
ovsswitch (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort attribute) +
+ +
+ +

P

+ + + +
+ +
ParallelRun (class in nepi.util.parallel) +
+ + +
parse_file() (in module nepi.data.processing.ccn.parser) +
+ +
+ +
(in module nepi.data.processing.ping.parser) +
+ +
+ +
parse_sfa_rspec() (nepi.util.sfarspec_proc.SfaRSpecProcessing method) +
+ + +
PATH (nepi.execution.trace.TraceAttr attribute) +
+ + +
path (nepi.resources.linux.ccn.ccnd.LinuxCCND attribute) +
+ + +
peer_map (nepi.resources.planetlab.plcapi.PLCAPI attribute) +
+ + +
pending (nepi.execution.scheduler.HeapScheduler attribute) +
+ + +
persist (nepi.execution.ec.ExperimentController attribute) +
+ + +
PFormats (class in nepi.util.plotter) +
+ + +
phy (nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel attribute) +
+ + +
phys (nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel attribute) +
+ + +
pi (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel attribute) +
+ + +
pid (nepi.resources.linux.application.LinuxApplication attribute) +
+ +
+ +
(nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication attribute) +
+ +
+ +
ping (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry attribute) +
+ + +
PlanetlabNode (class in nepi.resources.planetlab.node) +
+ + +
PlanetlabNs3FdUdpTunnel (class in nepi.resources.planetlab.ns3.fdudptunnel) +
+ + +
PlanetlabOVSPort (class in nepi.resources.planetlab.openvswitch.ovsport) +
+ + +
PlanetlabOVSSwitch (class in nepi.resources.planetlab.openvswitch.ovs) +
+ + +
PlanetlabSfaNode (class in nepi.resources.planetlab.sfa_node) +
+ + +
PlanetlabTap (class in nepi.resources.planetlab.tap) +
+ + +
PlanetlabTun (class in nepi.resources.planetlab.tun) +
+ + +
PlanetlabTunTapFdLink (class in nepi.resources.planetlab.ns3.tuntapfdlink) +
+ + +
PlanetlabVroute (class in nepi.resources.planetlab.vroute) +
+ + +
plapi (nepi.resources.planetlab.node.PlanetlabNode attribute) +
+ +
+ +
PLCAPI (class in nepi.resources.planetlab.plcapi) +
+ + +
PLCAPIFactory (class in nepi.resources.planetlab.plcapi) +
+ + +
plot() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.util.plotter.ECPlotter method) +
+ +
+ +
populate_factory() (in module nepi.execution.resource) +
+ + +
port_number (nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort attribute) +
+ + +
ppid (nepi.resources.linux.application.LinuxApplication attribute) +
+ + +
process_content_history() (in module nepi.data.processing.ccn.parser) +
+ + +
process_content_history_logs() (in module nepi.data.processing.ccn.parser) +
+ + +
ProcStatus (class in nepi.util.sshfuncs) +
+ + +
provision() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ +
+ +
provision_time (nepi.execution.resource.ResourceManager attribute) +
+ + +
PROVISIONED (nepi.execution.resource.ResourceState attribute) +
+ + +
publish() (nepi.resources.omf.omf_client.OMFClient method) +
+ + +
purge() (nepi.resources.omf.omf_client.OMFClient method) +
+ + +
put() (nepi.util.parallel.ParallelRun method) +
+ + +
put_nowait() (nepi.util.parallel.ParallelRun method) +
+ + +
pygccxml_version (nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
python_passfd_repo (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ + +
python_passfd_src (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ + +
python_passfd_version (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ + +
python_unshare_repo (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ + +
python_unshare_src (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ + +
python_unshare_version (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ +
+ +

Q

+ + + +
+ +
queue (nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice attribute) +
+ +
+ +
quit() (nepi.util.parallel.WorkerThread method) +
+ +
+ +

R

+ + + +
+ +
range (nepi.execution.attribute.Attribute attribute) +
+ + +
rcopy() (in module nepi.util.sshfuncs) +
+ + +
READY (nepi.execution.resource.ResourceState attribute) +
+ + +
ready (nepi.resources.omf.omf_client.OMFClient attribute) +
+ + +
ready_time (nepi.execution.resource.ResourceManager attribute) +
+ + +
recv_fd() (nepi.resources.ns3.ns3fdnetdevice.NS3BaseFdNetDevice method) +
+ + +
recv_msg() (in module nepi.resources.netns.netnsserver) +
+ +
+ +
(in module nepi.resources.ns3.ns3server) +
+ +
+ +
register() (nepi.resources.omf.omf_client.OMFClient method) +
+ + +
register_condition() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ +
+ +
register_connection() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ +
+ +
register_resource() (nepi.execution.ec.ExperimentController method) +
+ + +
register_type() (nepi.execution.resource.ResourceFactory class method) +
+ + +
release() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ + +
(nepi.resources.omf.omf5_api.OMF5API method) +
+ + +
(nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
(nepi.util.sfaapi.SFAAPI method) +
+ +
+ +
release_api() (nepi.resources.omf.omf_api_factory.OMFAPIFactory class method) +
+ + +
release_function() (nepi.resources.omf.messages_6.MessageHandler method) +
+ + +
release_time (nepi.execution.resource.ResourceManager attribute) +
+ + +
RELEASED (nepi.execution.ec.ECState attribute) +
+ +
+ +
(nepi.execution.resource.ResourceState attribute) +
+ +
+ +
remote_socket (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ +
+ +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ +
+ +
remove() (nepi.execution.scheduler.HeapScheduler method) +
+ + +
remove_all_from_slice() (nepi.util.sfaapi.SFAAPI method) +
+ + +
remove_packages() (nepi.resources.linux.node.LinuxNode method) +
+ + +
remove_packages_command() (in module nepi.resources.linux.debfuncs) +
+ +
+ +
(in module nepi.resources.linux.rpmfuncs) +
+ +
+ +
remove_resource() (nepi.execution.ec.ExperimentController method) +
+ + +
remove_resource_from_slice() (nepi.util.manifoldapi.MANIFOLDAPI method) +
+ +
+ +
(nepi.util.sfaapi.SFAAPI method) +
+ +
+ +
replace_args() (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ +
+ +
replace_kwargs() (nepi.resources.netns.netnswrapper.NetNSWrapper method) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ +
+ +
replace_paths() (nepi.resources.linux.application.LinuxApplication method) +
+ +
+ +
(nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ +
+ +
request_function() (nepi.resources.omf.messages_6.MessageHandler method) +
+ + +
reschedule_delay (nepi.execution.resource.ResourceManager attribute) +
+ + +
reserve() (nepi.execution.resource.ResourceManager method) +
+ + +
reserve_host() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ +
+ +
reserve_resource() (nepi.util.sfaapi.SFAAPI method) +
+ + +
Reserved (nepi.execution.attribute.Flags attribute) +
+ + +
RESERVED (nepi.execution.resource.ResourceState attribute) +
+ + +
reserved() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ +
+ +
(nepi.util.sfaapi.SFAAPI method) +
+ +
+ +
reserved_time (nepi.execution.resource.ResourceManager attribute) +
+ + +
resolve_hostname() (in module nepi.util.sshfuncs) +
+ + +
resource_types() (nepi.execution.resource.ResourceFactory class method) +
+ + +
ResourceAction (class in nepi.execution.resource) +
+ + +
ResourceFactory (class in nepi.execution.resource) +
+ + +
ResourceGateway (class in nepi.resources.omf.omf_resource) +
+ + +
ResourceManager (class in nepi.execution.resource) +
+ + +
resources (nepi.execution.ec.ExperimentController attribute) +
+ + +
ResourceState (class in nepi.execution.resource) +
+ + +
retract() (nepi.resources.omf.omf_client.OMFClient method) +
+ + +
rexec() (in module nepi.util.sshfuncs) +
+ + +
rgetpid() (in module nepi.util.sshfuncs) +
+ + +
rkill() (in module nepi.util.sshfuncs) +
+ + +
RM_FAILURE (nepi.execution.ec.FailureLevel attribute) +
+ + +
rmdir() (nepi.resources.linux.node.LinuxNode method) +
+ + +
rspawn() (in module nepi.util.sshfuncs) +
+ + +
rstatus() (in module nepi.util.sshfuncs) +
+ + +
run() (nepi.execution.runner.ExperimentRunner method) +
+ +
+ +
(nepi.resources.linux.node.LinuxNode method) +
+ + +
(nepi.util.parallel.WorkerThread method) +
+ +
+ +
run_and_wait() (nepi.resources.linux.node.LinuxNode method) +
+ + +
run_dir (nepi.execution.ec.ExperimentController attribute) +
+ + +
run_experiment() (nepi.execution.runner.ExperimentRunner method) +
+ + +
run_home (nepi.resources.linux.application.LinuxApplication attribute) +
+ +
+ +
(nepi.resources.linux.node.LinuxNode attribute) +
+ +
+ +
run_home() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ +
+ +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ +
+ +
run_id (nepi.execution.ec.ExperimentController attribute) +
+ + +
run_server() (in module nepi.resources.netns.netnsserver) +
+ +
+ +
(in module nepi.resources.ns3.ns3server) +
+ +
+ +
RUNNING (nepi.execution.ec.ECState attribute) +
+ +
+ +
(nepi.util.sshfuncs.ProcStatus attribute) +
+ +
+
+ +

S

+ + + +
+ +
save() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.util.serializer.ECSerializer method) +
+ +
+ +
schedule() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.scheduler.HeapScheduler method) +
+ +
+ +
script_path (nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger attribute) +
+ +
+ +
(nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger attribute) +
+ +
+ +
select_base_class() (in module nepi.resources.ns3.resource_manager_generator) +
+ + +
select_random_source() (nepi.util.netgraph.NetGraph method) +
+ + +
select_target_zero() (nepi.util.netgraph.NetGraph method) +
+ + +
send_msg() (nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
+ +
+ +
(nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ +
+ +
send_reply() (in module nepi.resources.netns.netnsserver) +
+ +
+ +
(in module nepi.resources.ns3.ns3server) +
+ +
+ +
send_stdin() (nepi.resources.omf.omf5_api.OMF5API method) +
+ + +
serialize() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.util.serializer.ECSerializer method) +
+ +
+ +
servers_on() (nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
+ + +
SET (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
+ +
+ +
(nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
+ +
+ +
set() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ + +
(nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
+ + +
(nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ + +
(nepi.resources.netns.netnsbase.NetNSBase method) +
+ + +
(nepi.resources.netns.netnsclient.NetNSClient method) +
+ + +
(nepi.resources.netns.netnswrapper.NetNSWrapper method) +
+ + +
(nepi.resources.ns3.ns3base.NS3Base method) +
+ + +
(nepi.resources.ns3.ns3client.NS3Client method) +
+ + +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ +
+ +
set_discovered() (nepi.execution.resource.ResourceManager method) +
+ + +
set_ec() (nepi.execution.ec.FailureManager method) +
+ + +
set_ec_failure() (nepi.execution.ec.FailureManager method) +
+ + +
set_failed() (nepi.execution.resource.ResourceManager method) +
+ + +
set_global() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager class method) +
+ +
+ +
set_hook_mtu() (nepi.resources.linux.interface.LinuxInterface method) +
+ + +
set_hook_up() (nepi.resources.linux.interface.LinuxInterface method) +
+ + +
set_provisioned() (nepi.execution.resource.ResourceManager method) +
+ + +
set_ready() (nepi.execution.resource.ResourceManager method) +
+ + +
set_released() (nepi.execution.resource.ResourceManager method) +
+ + +
set_reserved() (nepi.execution.resource.ResourceManager method) +
+ + +
set_source() (nepi.util.netgraph.NetGraph method) +
+ + +
set_started() (nepi.execution.resource.ResourceManager method) +
+ + +
set_state() (nepi.execution.resource.ResourceManager method) +
+ + +
set_state_time() (nepi.execution.resource.ResourceManager method) +
+ + +
set_stopped() (nepi.execution.resource.ResourceManager method) +
+ + +
set_target() (nepi.util.netgraph.NetGraph method) +
+ + +
set_value() (nepi.execution.attribute.Attribute method) +
+ + +
set_with_conditions() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ +
+ +
SFAAPI (class in nepi.util.sfaapi) +
+ + +
sfaapi (nepi.resources.omf.wilabt_node.WilabtSfaNode attribute) +
+ +
+ +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode attribute) +
+ +
+ +
SFAAPIFactory (class in nepi.util.sfaapi) +
+ + +
SfaRSpecProcessing (class in nepi.util.sfarspec_proc) +
+ + +
SFormats (class in nepi.util.serializer) +
+ +
+ +
share_dir (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
shell_escape() (in module nepi.util.sshfuncs) +
+ + +
SHUTDOWN (nepi.resources.netns.netnsserver.NetNSWrapperMessage attribute) +
+ +
+ +
(nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
+ +
+ +
shutdown() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.resources.linux.netns.netnsclient.LinuxNetNSClient method) +
+ + +
(nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ + +
(nepi.resources.netns.netnsclient.NetNSClient method) +
+ + +
(nepi.resources.netns.netnsemulation.NetNSEmulation method) +
+ + +
(nepi.resources.netns.netnswrapper.NetNSWrapper method) +
+ + +
(nepi.resources.ns3.ns3client.NS3Client method) +
+ + +
(nepi.resources.ns3.ns3simulation.NS3Simulation method) +
+ + +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ +
+ +
simulation (nepi.resources.linux.ns3.ns3client.LinuxNS3Client attribute) +
+ +
+ +
(nepi.resources.ns3.ns3base.NS3Base attribute) +
+ + +
(nepi.resources.ns3.ns3channel.NS3BaseChannel attribute) +
+ + +
(nepi.resources.ns3.ns3node.NS3BaseNode attribute) +
+ + +
(nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel attribute) +
+ + +
(nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel attribute) +
+ + +
(nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel attribute) +
+ +
+ +
SIZE (nepi.execution.trace.TraceAttr attribute) +
+ + +
sock_name (nepi.resources.linux.tap.LinuxTap attribute) +
+ + +
socket_name (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation attribute) +
+ +
+ +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ +
+ +
sources() (nepi.util.netgraph.NetGraph method) +
+ + +
src_dir (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
stabsformat() (in module nepi.util.timefuncs) +
+ + +
STAR (nepi.util.netgraph.TopologyType attribute) +
+ + +
START (nepi.execution.resource.ResourceAction attribute) +
+ +
+ +
(nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
+ +
+ +
start() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ + +
(nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ + +
(nepi.resources.ns3.ns3client.NS3Client method) +
+ + +
(nepi.resources.ns3.ns3simulation.NS3Simulation method) +
+ + +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ + +
(nepi.resources.omf.omf_client.OMFClient method) +
+ + +
(nepi.util.parallel.ParallelRun method) +
+ +
+ +
start_multicall() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
start_time (nepi.execution.resource.ResourceManager attribute) +
+ + +
start_with_conditions() (nepi.execution.resource.ResourceManager method) +
+ + +
STARTED (nepi.execution.resource.ResourceState attribute) +
+ + +
state (nepi.execution.resource.ResourceManager attribute) +
+ +
+ +
(nepi.resources.linux.application.LinuxApplication attribute) +
+ + +
(nepi.resources.linux.ccn.ccnd.LinuxCCND attribute) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation attribute) +
+ + +
(nepi.resources.linux.tap.LinuxTap attribute) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel attribute) +
+ + +
(nepi.resources.netns.netnsapplication.NetNSApplication attribute) +
+ + +
(nepi.resources.netns.netnsbase.NetNSBase attribute) +
+ + +
(nepi.resources.ns3.ns3application.NS3BaseApplication attribute) +
+ + +
(nepi.resources.ns3.ns3base.NS3Base attribute) +
+ +
+ +
state() (nepi.execution.ec.ExperimentController method) +
+ + +
status() (nepi.resources.linux.node.LinuxNode method) +
+ + +
stdin_function() (nepi.resources.omf.messages_5_4.MessageHandler method) +
+ + +
stdin_hook() (nepi.resources.omf.application.OMFApplication method) +
+ + +
STDOUT (class in nepi.util.sshfuncs) +
+ + +
stformat() (in module nepi.util.timefuncs) +
+ + +
STOP (nepi.execution.resource.ResourceAction attribute) +
+ +
+ +
(nepi.resources.ns3.ns3server.NS3WrapperMessage attribute) +
+ +
+ +
stop() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ + +
(nepi.resources.linux.ns3.ns3client.LinuxNS3Client method) +
+ + +
(nepi.resources.ns3.ns3client.NS3Client method) +
+ + +
(nepi.resources.ns3.ns3simulation.NS3Simulation method) +
+ + +
(nepi.resources.ns3.ns3wrapper.NS3Wrapper method) +
+ +
+ +
stop_time (nepi.execution.resource.ResourceManager attribute) +
+ + +
stop_with_conditions() (nepi.execution.resource.ResourceManager method) +
+ + +
STOPPED (nepi.execution.resource.ResourceState attribute) +
+ + +
store_path (nepi.resources.all.collector.Collector attribute) +
+ + +
STREAM (nepi.execution.trace.TraceAttr attribute) +
+ + +
String (nepi.execution.attribute.Types attribute) +
+ + +
subscribe() (nepi.resources.omf.omf_client.OMFClient method) +
+ + +
subscriptions() (nepi.resources.omf.omf_client.OMFClient method) +
+ + +
switch (nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface attribute) +
+ + +
sync() (nepi.util.parallel.ParallelRun method) +
+ +
+ +

T

+ + + +
+ +
tap (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
+ +
+ +
(nepi.resources.planetlab.ns3.tuntapfdlink.PlanetlabTunTapFdLink attribute) +
+ + +
(nepi.resources.planetlab.vroute.PlanetlabVroute attribute) +
+ +
+ +
tapnode (nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink attribute) +
+ + +
targets() (nepi.util.netgraph.NetGraph method) +
+ + +
Task (class in nepi.execution.scheduler) +
+ + +
TaskStatus (class in nepi.execution.scheduler) +
+ + +
tdiff() (in module nepi.util.timefuncs) +
+ + +
tdiffsec() (in module nepi.util.timefuncs) +
+ + +
template_attributes() (in module nepi.resources.ns3.resource_manager_generator) +
+ + +
template_traces() (in module nepi.resources.ns3.resource_manager_generator) +
+ + +
terminate_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
+ +
+ +
(nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
(nepi.resources.linux.tap.LinuxTap method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ +
+ +
TERMINATED (nepi.execution.ec.ECState attribute) +
+ + +
test() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
TestbedtoGateway (nepi.resources.omf.omf_resource.ResourceGateway attribute) +
+ + +
tnow() (in module nepi.util.timefuncs) +
+ + +
to_type() (in module nepi.util.parsers.xml_parser) +
+ +
+ +
to_xml() (nepi.util.parsers.xml_parser.ECXMLParser method) +
+ + +
topo_type (nepi.util.netgraph.NetGraph attribute) +
+ + +
topology (nepi.util.netgraph.NetGraph attribute) +
+ + +
TopologyType (class in nepi.util.netgraph) +
+ + +
Trace (class in nepi.execution.trace) +
+ + +
trace() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ + +
(nepi.resources.linux.application.LinuxApplication method) +
+ + +
(nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ + +
(nepi.resources.netns.netnsbase.NetNSBase method) +
+ + +
(nepi.resources.ns3.ns3base.NS3Base method) +
+ + +
(nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication method) +
+ + +
(nepi.resources.omf.application.OMFApplication method) +
+ +
+ +
trace_enabled() (nepi.execution.ec.ExperimentController method) +
+ +
+ +
(nepi.execution.resource.ResourceManager method) +
+ +
+ +
trace_filepath() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
TraceAttr (class in nepi.execution.trace) +
+ + +
traceroute (nepi.resources.linux.ccn.fibentry.LinuxFIBEntry attribute) +
+ + +
TREE (nepi.util.netgraph.TopologyType attribute) +
+ + +
tsformat() (in module nepi.util.timefuncs) +
+ + +
type (nepi.execution.attribute.Attribute attribute) +
+ + +
Types (class in nepi.execution.attribute) +
+ +
+ +

U

+ + + +
+ +
UBUNTU (nepi.resources.linux.node.OSType attribute) +
+ + +
udp_connect() (nepi.resources.linux.tap.LinuxTap method) +
+ + +
unblacklist_host() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
unenroll_topic() (nepi.resources.omf.omf6_api.OMF6API method) +
+ + +
unregister() (nepi.resources.omf.omf_client.OMFClient method) +
+ + +
unregister_condition() (nepi.execution.resource.ResourceManager method) +
+ + +
unregister_connection() (nepi.execution.resource.ResourceManager method) +
+ + +
unreserve_host() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
unsubscribe() (nepi.resources.omf.omf_client.OMFClient method) +
+ + +
update_slice() (nepi.resources.planetlab.plcapi.PLCAPI method) +
+ + +
upload() (nepi.resources.linux.node.LinuxNode method) +
+ + +
upload_binaries() (nepi.resources.linux.application.LinuxApplication method) +
+ +
+ +
upload_code() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
upload_command() (nepi.resources.linux.node.LinuxNode method) +
+ + +
upload_extra_sources() (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ +
+ +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ +
+ +
upload_files() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
upload_libraries() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
upload_sources() (nepi.resources.linux.application.LinuxApplication method) +
+ +
+ +
(nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ + +
(nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ + +
(nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink method) +
+ + +
(nepi.resources.linux.route.LinuxRoute method) +
+ + +
(nepi.resources.linux.tap.LinuxTap method) +
+ + +
(nepi.resources.planetlab.ns3.tuntapfdlink.PlanetlabTunTapFdLink method) +
+ + +
(nepi.resources.planetlab.tap.PlanetlabTap method) +
+ + +
(nepi.resources.planetlab.vroute.PlanetlabVroute method) +
+ +
+ +
upload_start_command() (nepi.resources.linux.application.LinuxApplication method) +
+ +
+ +
(nepi.resources.linux.ccn.ccncontent.LinuxCCNContent method) +
+ + +
(nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
+ + +
(nepi.resources.linux.ccn.ccnr.LinuxCCNR method) +
+ + +
(nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
+ + +
(nepi.resources.linux.mtr.LinuxMtr method) +
+ + +
(nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ + +
(nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink method) +
+ + +
(nepi.resources.linux.ping.LinuxPing method) +
+ + +
(nepi.resources.linux.route.LinuxRoute method) +
+ + +
(nepi.resources.linux.tap.LinuxTap method) +
+ + +
(nepi.resources.linux.traceroute.LinuxTraceroute method) +
+ + +
(nepi.resources.linux.udptest.LinuxUdpTest method) +
+ + +
(nepi.resources.planetlab.tap.PlanetlabTap method) +
+ + +
(nepi.resources.planetlab.vroute.PlanetlabVroute method) +
+ +
+ +
upload_stdin() (nepi.resources.linux.application.LinuxApplication method) +
+ + +
use_deb (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
use_rpm (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
usr_dir (nepi.resources.linux.node.LinuxNode attribute) +
+ + +
uuid (nepi.resources.netns.netnsbase.NetNSBase attribute) +
+ +
+ +
(nepi.resources.ns3.ns3base.NS3Base attribute) +
+ +
+
+ +

V

+ + + +
+ +
valid_connection() (nepi.execution.resource.ResourceManager method) +
+ +
+ +
(nepi.resources.all.collector.Collector method) +
+ + +
(nepi.resources.linux.application.LinuxApplication method) +
+ + +
(nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication method) +
+ + +
(nepi.resources.linux.ccn.ccncat.LinuxCCNCat method) +
+ + +
(nepi.resources.linux.ccn.ccncontent.LinuxCCNContent method) +
+ + +
(nepi.resources.linux.ccn.ccnd.LinuxCCND method) +
+ + +
(nepi.resources.linux.ccn.ccnpeek.LinuxCCNPeek method) +
+ + +
(nepi.resources.linux.ccn.ccnping.LinuxCCNPing method) +
+ + +
(nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer method) +
+ + +
(nepi.resources.linux.ccn.ccnpoke.LinuxCCNPoke method) +
+ + +
(nepi.resources.linux.ccn.ccnr.LinuxCCNR method) +
+ + +
(nepi.resources.linux.ccn.fibentry.LinuxFIBEntry method) +
+ + +
(nepi.resources.linux.channel.LinuxChannel method) +
+ + +
(nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
+ + +
(nepi.resources.linux.interface.LinuxInterface method) +
+ + +
(nepi.resources.linux.mtr.LinuxMtr method) +
+ + +
(nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ + +
(nepi.resources.linux.node.LinuxNode method) +
+ + +
(nepi.resources.linux.nping.LinuxNPing method) +
+ + +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ + +
(nepi.resources.linux.ping.LinuxPing method) +
+ + +
(nepi.resources.linux.tap.LinuxTap method) +
+ + +
(nepi.resources.linux.tcpdump.LinuxTcpdump method) +
+ + +
(nepi.resources.linux.traceroute.LinuxTraceroute method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptest.LinuxUdpTest method) +
+ + +
(nepi.resources.omf.application.OMFApplication method) +
+ + +
(nepi.resources.omf.channel.OMFChannel method) +
+ + +
(nepi.resources.omf.interface.OMFWifiInterface method) +
+ + +
(nepi.resources.omf.node.OMFNode method) +
+ + +
(nepi.resources.omf.wilabt_node.WilabtSfaNode method) +
+ + +
(nepi.resources.planetlab.node.PlanetlabNode method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ + +
(nepi.resources.planetlab.sfa_node.PlanetlabSfaNode method) +
+ + +
(nepi.resources.planetlab.tap.PlanetlabTap method) +
+ + +
(nepi.resources.planetlab.vroute.PlanetlabVroute method) +
+ +
+ +
value (nepi.execution.attribute.Attribute attribute) +
+ + +
verify() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
verify_connection() (nepi.resources.linux.gretunnel.LinuxGRETunnel method) +
+ +
+ +
(nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
(nepi.resources.linux.tap.LinuxTap method) +
+ + +
(nepi.resources.linux.tunnel.LinuxTunnel method) +
+ + +
(nepi.resources.linux.udptunnel.LinuxUdpTunnel method) +
+ + +
(nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort method) +
+ +
+ +
version (nepi.resources.linux.ccn.ccnd.LinuxCCND attribute) +
+ +
+ +
(nepi.resources.linux.ns3.ccn.ns3ccnddceapplication.LinuxNS3DceCCND attribute) +
+ +
+
+ +
vif_name_file (nepi.resources.planetlab.tap.PlanetlabTap attribute) +
+ + +
vif_prefix (nepi.resources.linux.tap.LinuxTap attribute) +
+ + +
vif_type (nepi.resources.linux.tap.LinuxTap attribute) +
+ + +
vif_type_flag (nepi.resources.linux.tap.LinuxTap attribute) +
+ +
+ +

W

+ + + +
+ +
wait() (nepi.execution.ec.ExperimentController method) +
+ + +
wait_deployed() (nepi.execution.ec.ExperimentController method) +
+ + +
wait_file() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ +
+ +
(nepi.resources.linux.tap.LinuxTap method) +
+ +
+ +
wait_finished() (nepi.execution.ec.ExperimentController method) +
+ + +
wait_local_port() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
wait_pid() (nepi.resources.linux.node.LinuxNode method) +
+ + +
wait_released() (nepi.execution.ec.ExperimentController method) +
+ + +
wait_remote_socket() (nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation method) +
+ +
+ +
(nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation method) +
+ +
+
+ +
wait_result() (nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel method) +
+ + +
wait_run() (nepi.resources.linux.node.LinuxNode method) +
+ + +
wait_started() (nepi.execution.ec.ExperimentController method) +
+ + +
wait_vif_name() (nepi.resources.planetlab.tap.PlanetlabTap method) +
+ + +
warning() (nepi.util.logger.Logger method) +
+ + +
WilabtSfaNode (class in nepi.resources.omf.wilabt_node) +
+ + +
WorkerThread (class in nepi.util.parallel) +
+ + +
WorkerThread.QUIT (class in nepi.util.parallel) +
+ +
+ +

X

+ + + +
+ +
XML (nepi.util.serializer.SFormats attribute) +
+ + +
xmldecode() (in module nepi.util.parsers.xml_parser) +
+ +
+ +
xmlencode() (in module nepi.util.parsers.xml_parser) +
+ +
+ + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/index.html b/doc/sphinx/_build/html/index.html new file mode 100644 index 00000000..f5861b3c --- /dev/null +++ b/doc/sphinx/_build/html/index.html @@ -0,0 +1,201 @@ + + + + + + + + NEPI modules — NEPI 3.0 documentation + + + + + + + + + + + + +
+
+

Table Of Contents

+ + +

This Page

+ + + +
+
+ +
+
+
+
+ +
+

NEPI modules¶

+

This page documents the NEPI source code. It presents the NEPI core modules, the Platform resource modules (i.e. drivers to manage platforms), and other miscellaneous classes.

+
+

Core modules¶

+
+
+
+
+
+

Platform modules¶

+
+
+
+
+
+

Miscellaneous modules¶

+
+
+
+
+
    +
+
+
+
+
+

Indices and tables¶

+ +
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/objects.inv b/doc/sphinx/_build/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..2c3613a6160d0fae8c9c7b854f44032b594d045c GIT binary patch literal 16497 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�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 + + + + + + + Python Module Index — NEPI 3.0 documentation + + + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+
+ + +

Python Module Index

+ +
+ n +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ n
+ nepi +
    + nepi.data +
    + nepi.data.processing +
    + nepi.data.processing.ccn +
    + nepi.data.processing.ccn.parser +
    + nepi.data.processing.ping +
    + nepi.data.processing.ping.parser +
    + nepi.execution +
    + nepi.execution.attribute +
    + nepi.execution.ec +
    + nepi.execution.resource +
    + nepi.execution.runner +
    + nepi.execution.scheduler +
    + nepi.execution.tags +
    + nepi.execution.trace +
    + nepi.resources +
    + nepi.resources.all +
    + nepi.resources.all.collector +
    + nepi.resources.linux +
    + nepi.resources.linux.application +
    + nepi.resources.linux.ccn +
    + nepi.resources.linux.ccn.ccnapplication +
    + nepi.resources.linux.ccn.ccncat +
    + nepi.resources.linux.ccn.ccncontent +
    + nepi.resources.linux.ccn.ccnd +
    + nepi.resources.linux.ccn.ccnpeek +
    + nepi.resources.linux.ccn.ccnping +
    + nepi.resources.linux.ccn.ccnpingserver +
    + nepi.resources.linux.ccn.ccnpoke +
    + nepi.resources.linux.ccn.ccnr +
    + nepi.resources.linux.ccn.fibentry +
    + nepi.resources.linux.channel +
    + nepi.resources.linux.debfuncs +
    + nepi.resources.linux.gretunnel +
    + nepi.resources.linux.interface +
    + nepi.resources.linux.mtr +
    + nepi.resources.linux.netns +
    + nepi.resources.linux.netns.netnsclient +
    + nepi.resources.linux.netns.netnsemulation +
    + nepi.resources.linux.node +
    + nepi.resources.linux.nping +
    + nepi.resources.linux.ns3 +
    + nepi.resources.linux.ns3.ccn +
    + nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication +
    + nepi.resources.linux.ns3.ccn.ns3ccndceapplication +
    + nepi.resources.linux.ns3.ccn.ns3ccnddceapplication +
    + nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication +
    + nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication +
    + nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication +
    + nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication +
    + nepi.resources.linux.ns3.fdudptunnel +
    + nepi.resources.linux.ns3.ns3client +
    + nepi.resources.linux.ns3.ns3dceapplication +
    + nepi.resources.linux.ns3.ns3pingdceapplication +
    + nepi.resources.linux.ns3.ns3simulation +
    + nepi.resources.linux.ns3.tuntapfdlink +
    + nepi.resources.linux.ping +
    + nepi.resources.linux.route +
    + nepi.resources.linux.rpmfuncs +
    + nepi.resources.linux.tap +
    + nepi.resources.linux.tcpdump +
    + nepi.resources.linux.traceroute +
    + nepi.resources.linux.tun +
    + nepi.resources.linux.tunnel +
    + nepi.resources.linux.udptest +
    + nepi.resources.linux.udptunnel +
    + nepi.resources.netns +
    + nepi.resources.netns.netnsapplication +
    + nepi.resources.netns.netnsbase +
    + nepi.resources.netns.netnsclient +
    + nepi.resources.netns.netnsemulation +
    + nepi.resources.netns.netnsinterface +
    + nepi.resources.netns.netnsipv4address +
    + nepi.resources.netns.netnsnode +
    + nepi.resources.netns.netnsnodeinterface +
    + nepi.resources.netns.netnsroute +
    + nepi.resources.netns.netnsserver +
    + nepi.resources.netns.netnsswitch +
    + nepi.resources.netns.netnswrapper +
    + nepi.resources.netns.netnswrapper_debug +
    + nepi.resources.ns3 +
    + nepi.resources.ns3.classes +
    + nepi.resources.ns3.classes.aarf_wifi_manager +
    + nepi.resources.ns3.classes.aarfcd_wifi_manager +
    + nepi.resources.ns3.classes.adhoc_wifi_mac +
    + nepi.resources.ns3.classes.aloha_noack_net_device +
    + nepi.resources.ns3.classes.amrr_wifi_manager +
    + nepi.resources.ns3.classes.ap_wifi_mac +
    + nepi.resources.ns3.classes.arf_wifi_manager +
    + nepi.resources.ns3.classes.arp_l3protocol +
    + nepi.resources.ns3.classes.base_station_net_device +
    + nepi.resources.ns3.classes.binary_error_model +
    + nepi.resources.ns3.classes.binary_error_sixlow_model +
    + nepi.resources.ns3.classes.bridge_channel +
    + nepi.resources.ns3.classes.bridge_net_device +
    + nepi.resources.ns3.classes.bulk_send_application +
    + nepi.resources.ns3.classes.burst_error_model +
    + nepi.resources.ns3.classes.cara_wifi_manager +
    + nepi.resources.ns3.classes.constant_acceleration_mobility_model +
    + nepi.resources.ns3.classes.constant_position_mobility_model +
    + nepi.resources.ns3.classes.constant_rate_wifi_manager +
    + nepi.resources.ns3.classes.constant_speed_propagation_delay_model +
    + nepi.resources.ns3.classes.constant_velocity_mobility_model +
    + nepi.resources.ns3.classes.cost231propagation_loss_model +
    + nepi.resources.ns3.classes.csma_channel +
    + nepi.resources.ns3.classes.csma_net_device +
    + nepi.resources.ns3.classes.drop_tail_queue +
    + nepi.resources.ns3.classes.dsrdsr_routing +
    + nepi.resources.ns3.classes.emu_net_device +
    + nepi.resources.ns3.classes.error_channel +
    + nepi.resources.ns3.classes.error_channel_sixlow +
    + nepi.resources.ns3.classes.error_net_device +
    + nepi.resources.ns3.classes.fd_net_device +
    + nepi.resources.ns3.classes.fixed_rss_loss_model +
    + nepi.resources.ns3.classes.friis_propagation_loss_model +
    + nepi.resources.ns3.classes.gauss_markov_mobility_model +
    + nepi.resources.ns3.classes.hierarchical_mobility_model +
    + nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model +
    + nepi.resources.ns3.classes.icmpv4l4protocol +
    + nepi.resources.ns3.classes.icmpv6l4protocol +
    + nepi.resources.ns3.classes.ideal_wifi_manager +
    + nepi.resources.ns3.classes.ipv4l3protocol +
    + nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model +
    + nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model +
    + nepi.resources.ns3.classes.jakes_propagation_loss_model +
    + nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model +
    + nepi.resources.ns3.classes.list_error_model +
    + nepi.resources.ns3.classes.log_distance_propagation_loss_model +
    + nepi.resources.ns3.classes.loopback_net_device +
    + nepi.resources.ns3.classes.lr_wpan_net_device +
    + nepi.resources.ns3.classes.lte_enb_net_device +
    + nepi.resources.ns3.classes.lte_simple_net_device +
    + nepi.resources.ns3.classes.lte_ue_net_device +
    + nepi.resources.ns3.classes.matrix_propagation_loss_model +
    + nepi.resources.ns3.classes.mesh_point_device +
    + nepi.resources.ns3.classes.mesh_wifi_interface_mac +
    + nepi.resources.ns3.classes.minstrel_wifi_manager +
    + nepi.resources.ns3.classes.multi_model_spectrum_channel +
    + nepi.resources.ns3.classes.nakagami_propagation_loss_model +
    + nepi.resources.ns3.classes.nist_error_rate_model +
    + nepi.resources.ns3.classes.node +
    + nepi.resources.ns3.classes.non_communicating_net_device +
    + nepi.resources.ns3.classes.ocb_wifi_mac +
    + nepi.resources.ns3.classes.oh_buildings_propagation_loss_model +
    + nepi.resources.ns3.classes.okumura_hata_propagation_loss_model +
    + nepi.resources.ns3.classes.on_off_application +
    + nepi.resources.ns3.classes.onoe_wifi_manager +
    + nepi.resources.ns3.classes.packet_sink +
    + nepi.resources.ns3.classes.ping6 +
    + nepi.resources.ns3.classes.point_to_point_channel +
    + nepi.resources.ns3.classes.point_to_point_net_device +
    + nepi.resources.ns3.classes.point_to_point_remote_channel +
    + nepi.resources.ns3.classes.radvd +
    + nepi.resources.ns3.classes.random_direction2d_mobility_model +
    + nepi.resources.ns3.classes.random_propagation_delay_model +
    + nepi.resources.ns3.classes.random_propagation_loss_model +
    + nepi.resources.ns3.classes.random_walk2d_mobility_model +
    + nepi.resources.ns3.classes.random_waypoint_mobility_model +
    + nepi.resources.ns3.classes.range_propagation_loss_model +
    + nepi.resources.ns3.classes.rate_error_model +
    + nepi.resources.ns3.classes.receive_list_error_model +
    + nepi.resources.ns3.classes.red_queue +
    + nepi.resources.ns3.classes.rraa_wifi_manager +
    + nepi.resources.ns3.classes.simple_channel +
    + nepi.resources.ns3.classes.simple_net_device +
    + nepi.resources.ns3.classes.single_model_spectrum_channel +
    + nepi.resources.ns3.classes.six_low_pan_net_device +
    + nepi.resources.ns3.classes.sta_wifi_mac +
    + nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model +
    + nepi.resources.ns3.classes.subscriber_station_net_device +
    + nepi.resources.ns3.classes.tap_bridge +
    + nepi.resources.ns3.classes.tcp_l4protocol +
    + nepi.resources.ns3.classes.three_log_distance_propagation_loss_model +
    + nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model +
    + nepi.resources.ns3.classes.uan_channel +
    + nepi.resources.ns3.classes.udp_client +
    + nepi.resources.ns3.classes.udp_echo_client +
    + nepi.resources.ns3.classes.udp_echo_server +
    + nepi.resources.ns3.classes.udp_l4protocol +
    + nepi.resources.ns3.classes.udp_server +
    + nepi.resources.ns3.classes.udp_trace_client +
    + nepi.resources.ns3.classes.v4ping +
    + nepi.resources.ns3.classes.virtual_net_device +
    + nepi.resources.ns3.classes.waypoint_mobility_model +
    + nepi.resources.ns3.classes.wifi_net_device +
    + nepi.resources.ns3.classes.yans_error_rate_model +
    + nepi.resources.ns3.classes.yans_wifi_channel +
    + nepi.resources.ns3.classes.yans_wifi_phy +
    + nepi.resources.ns3.ns3application +
    + nepi.resources.ns3.ns3arpl3protocol +
    + nepi.resources.ns3.ns3base +
    + nepi.resources.ns3.ns3ccndceapplication +
    + nepi.resources.ns3.ns3channel +
    + nepi.resources.ns3.ns3client +
    + nepi.resources.ns3.ns3dceapplication +
    + nepi.resources.ns3.ns3dcehelper +
    + nepi.resources.ns3.ns3errormodel +
    + nepi.resources.ns3.ns3errorratemodel +
    + nepi.resources.ns3.ns3fdnetdevice +
    + nepi.resources.ns3.ns3icmpv4l4protocol +
    + nepi.resources.ns3.ns3ipv4l3protocol +
    + nepi.resources.ns3.ns3mobilitymodel +
    + nepi.resources.ns3.ns3netdevice +
    + nepi.resources.ns3.ns3node +
    + nepi.resources.ns3.ns3pipechanel +
    + nepi.resources.ns3.ns3propagationdelaymodel +
    + nepi.resources.ns3.ns3propagationlossmodel +
    + nepi.resources.ns3.ns3queue +
    + nepi.resources.ns3.ns3route +
    + nepi.resources.ns3.ns3server +
    + nepi.resources.ns3.ns3simulation +
    + nepi.resources.ns3.ns3wifichannel +
    + nepi.resources.ns3.ns3wifimac +
    + nepi.resources.ns3.ns3wifinetdevice +
    + nepi.resources.ns3.ns3wifiphy +
    + nepi.resources.ns3.ns3wifiremotestationmanager +
    + nepi.resources.ns3.ns3wrapper +
    + nepi.resources.ns3.ns3wrapper_debug +
    + nepi.resources.ns3.resource_manager_generator +
    + nepi.resources.omf +
    + nepi.resources.omf.application +
    + nepi.resources.omf.channel +
    + nepi.resources.omf.interface +
    + nepi.resources.omf.messages_5_4 +
    + nepi.resources.omf.messages_6 +
    + nepi.resources.omf.node +
    + nepi.resources.omf.omf5_api +
    + nepi.resources.omf.omf6_api +
    + nepi.resources.omf.omf6_parser +
    + nepi.resources.omf.omf_api_factory +
    + nepi.resources.omf.omf_client +
    + nepi.resources.omf.omf_resource +
    + nepi.resources.omf.wilabt_node +
    + nepi.resources.planetlab +
    + nepi.resources.planetlab.node +
    + nepi.resources.planetlab.ns3 +
    + nepi.resources.planetlab.ns3.fdudptunnel +
    + nepi.resources.planetlab.ns3.tuntapfdlink +
    + nepi.resources.planetlab.openvswitch +
    + nepi.resources.planetlab.openvswitch.ovs +
    + nepi.resources.planetlab.openvswitch.ovsport +
    + nepi.resources.planetlab.plcapi +
    + nepi.resources.planetlab.sfa_node +
    + nepi.resources.planetlab.tap +
    + nepi.resources.planetlab.tun +
    + nepi.resources.planetlab.vroute +
    + nepi.util +
    + nepi.util.environ +
    + nepi.util.execfuncs +
    + nepi.util.guid +
    + nepi.util.logger +
    + nepi.util.manifoldapi +
    + nepi.util.netgraph +
    + nepi.util.parallel +
    + nepi.util.parsers +
    + nepi.util.parsers.xml_parser +
    + nepi.util.plotter +
    + nepi.util.rmatcher +
    + nepi.util.serializer +
    + nepi.util.sfaapi +
    + nepi.util.sfarspec_proc +
    + nepi.util.sshfuncs +
    + nepi.util.statfuncs +
    + nepi.util.timefuncs +
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/search.html b/doc/sphinx/_build/html/search.html new file mode 100644 index 00000000..fff7c622 --- /dev/null +++ b/doc/sphinx/_build/html/search.html @@ -0,0 +1,105 @@ + + + + + + + + Search — NEPI 3.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+
+ +

Search

+
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/sphinx/_build/html/searchindex.js b/doc/sphinx/_build/html/searchindex.js new file mode 100644 index 00000000..163da033 --- /dev/null +++ b/doc/sphinx/_build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({envversion:42,terms:{get_slice_resourc:16,get_object:[20,6],wait_start:10,prefix:[16,1],wait_local_port:8,nthread:10,concret:10,ns3ccnpeekdceappl:[8,12,1,21],linuxccnpok:0,ns3basestationnetdevic:11,everi:16,do_releas:[8,1,19,9,2,10,13,4],ns3subscriberstationnetdevic:11,manifoldapi:[12,17],ns3fdnetdevic:[12,21],cmd:[16,1],upload:[1,4],netns_vers:2,sliceid:4,verif:[4,9],enable_trac:10,ns3randompropagationdelaymodel:11,histor:3,consequ:10,second:[10,16,4],aggreg:[3,16],linuxtcpdump:1,udp_l4protocol:[12,21,6],even:1,ns3pingdceappl:[12,1,21],messages_6:[12,21],omf6_api:[12,21],introspect:6,adhoc:16,ns3apwifimac:11,"new":[10,16,4],net:[1,4],topolog:[3,16],ovsswitch:19,linuxp:1,controlmast:16,omfappl:4,ns3fixedrsslossmodel:11,path:[0,8,1,2,10,16,3,4,22],taskstatu:10,ns3udpl4protocol:11,okumura_hata_propagation_loss_model:[12,21,6],unreserve_host:9,datetim:16,endpoint_mkdir:[8,1],realeas:10,sdate:16,countn:3,unix:4,linuxnod:[1,9],plot:[10,16],describ:10,would:1,omf_resourc:[12,21],call:[10,16,4,9],ns3dcehelp:[12,21],type:[19,10,13,16,4,23],until:[8,1,9,2,10,16,4],heappop:10,ns3constantvelocitymobilitymodel:11,relat:[10,1,6],notic:[1,4],warn:16,parse_fil:[3,22],get_platform:10,register_resourc:10,hold:[16,1],yans_wifi_phi:[12,21,6],uploadin:1,must:[10,16,1],join:16,err:[16,1],pid:[16,1,6],work:[16,1],spec:16,server_kei:16,get_provision_tim:10,upload_start_command:[8,0,1,9,2],root:[10,16,4],overrid:10,set_stop:10,unregister_condit:10,indic:16,rgister:10,ns3binaryerrorsixlowmodel:11,want:[1,4],prefixlen:16,ns3loopbacknetdevic:11,end:[16,1,4],fail_sfaapi:[4,9],how:1,sever:10,env:[16,1,4],peer_map:9,udp_serv:[12,21,6],src_dir:[8,1,2],config:16,connect_timeout:[16,1,4],ns3mobilitymodel:[12,21],confid:10,ns3tapbridg:11,ladder:16,after:[10,16,19,4,9],openvswitch:[12,21,9],lab:9,befor:[10,16,1,19],mesh:16,arch:9,parallel:[12,17],slice_id:16,clean_hom:1,ns3server:[12,21],credenti:[10,16,4],content_histori:3,receiv:[10,4],environ:[12,1,17,4],order:[10,16,4],netn:[12,1,21],sta_wifi_mac:[12,21,6],ocb_wifi_mac:[12,21,6],uuid:[20,6],reserve_resourc:16,filter_existing_fil:1,select_target_zero:16,persist:[10,16,1,4],cred:4,them:10,thei:[16,1,4],bootstrapf:9,safe:[10,16],ostyp:1,stop_with_condit:10,maxqueu:16,interrupt:10,wait_releas:10,min_run:10,pformat:16,each:[10,3,4,9,16],debug:[16,1,20,6],linuxtun:1,mean:[10,1,4],onoe_wifi_manag:[12,21,6],myslic:16,range_propagation_loss_model:[12,21,6],pl_user:9,point_to_point_net_devic:[12,21,6],csma_net_devic:[12,21,6],upload_sourc:[7,8,1,9,2],collector:[12,21],network:[10,16],dst:1,linuxns3cli:8,content:17,nito:4,linear:16,use_rpm:1,free:10,standard:16,netnswrappermessag:20,sigkil:16,fcdistro:9,store_path:13,linuxccncat:0,experimentid:4,filter:[10,16,9],unabl:1,lte_ue_net_devic:[12,21,6],onto:16,rang:10,netns_src:2,edge_net_annot:16,clsinit_copi:10,independ:10,restrict:10,hook:4,instruct:1,get_o:1,messag:[10,3,4],ns3tworaygroundpropagationlossmodel:11,sleekxmpp:4,consol:1,log_funct:4,tool:[16,1],wlab17:4,alreadi:[10,16,1],pl_host:9,set_ec_failur:10,target:[16,4],keyword:9,provid:[10,3,1],tree:16,"final":10,assign_control:19,provis:[10,16,4,9],ns3errormodel:[12,21],ccn_client_helper_uuid:6,runner:[12,17],execute_command:1,ns3lteenbnetdevic:11,wait_pid:1,log_distance_propagation_loss_model:[12,21,6],recreat:10,linuxappl:[0,8,1,19,2,9],ns3simul:[12,1,21],fname:3,lte_simple_net_devic:[12,21,6],ns3wrapper:[12,21],port_numb:19,usernam:[16,9],ns3channel:[12,21],register_typ:10,mesh_point_devic:[12,21,6],planetlabovsport:19,don:4,random_propagation_loss_model:[12,21,6],doe:[10,16,19,9],dump_factori:[20,6],get_help:10,declar:10,release_tim:10,dot:16,frcp_configur:4,servers_on:19,random:16,dirpath:[10,16],get_resourc:10,hybrid_buildings_propagation_loss_model:[12,21,6],find_typ:10,fail_node_not_al:[4,9],involv:10,absolut:[10,16],udp_trace_cli:[12,21,6],explain:[],configur:[10,0,4,8],stanza:4,than:10,modenapl:16,busi:1,folder:[10,16,1],timefunc:[12,17],create_ns3_rm:6,resourcemang:10,stop:[6,8,1,19,2,10,4],sfaapi:[12,17,4,9],udptunnel:[12,21],report:10,ideal_wifi_manag:[12,21,6],symmetr:10,ns3_set:6,omf5_api:[12,21],ns3constantpositionmobilitymodel:11,method:[6,1,9,10,20,16,4],check_releas:4,human:10,multi_model_spectrum_channel:[12,21,6],result:[10,16,1],ns3aarfcdwifimanag:11,respons:[10,1],fail:10,fd_net_devic:[12,21,6],dsrdsr_rout:[12,21,6],subject:10,discoveri:10,endpoint_nod:8,figur:[10,16],ns3applic:[12,21],dce_application_lock:6,udp_echo_cli:[12,21,6],res_id:4,remote_span:16,attribut:[12,17],accord:16,omf:[10,12,21],ns3_src_locat:8,ns3basemobilitymodel:[11,6],get_p2p_info:16,ovsport:[12,21,9],omf6_pars:[12,21],oml:16,extens:[10,5,9],advertis:16,ns3_build_loc:8,howev:[10,16],lte_enb_net_devic:[12,21,6],login:[16,9],strict_host_check:[16,1,4],ns3bridgechannel:11,slice_tag_id:9,nicta:4,guid:[0,6,7,8,12,1,19,9,2,10,13,11,14,17,4,20],assum:[10,16],ns3listerrormodel:11,xmldecod:23,been:[10,16,4],enrol:4,gre_en:1,terminate_connect:[8,1,19],unsubscrib:4,ns3basenetdevic:[11,6],basic:10,endpoint1:[8,1],endpoint2:[8,1],csma_channel:[12,21,6],run_serv:[20,6],hpcbench:1,xml_parser:[16,12],ani:[10,1,4,9],ns3basearpl3protocol:[11,6],blacklist_resourc:16,child:[10,4],get_opt:[20,6],dce_manager_lock:6,ident:16,servic:[16,9],properti:[16,4,9],sourceforg:1,sfarspecprocess:16,check_readi:4,spawn:[16,1],applic:[10,12,21],"0x7f028ff15bb0":16,set_discov:10,ityp:4,kwarg:[6,8,2,10,20,16],make_dict_rec:16,conn:[20,6],sfa_nod:[12,21],ccnr:[12,1,21],perform:10,make:[10,16],ccnd:[3,12,1,21],complex:9,configure_ip:4,ns3friispropagationlossmodel:11,complet:[10,9],parse_sfa_rspec:16,do_deploi:[0,6,8,1,19,9,2,10,13,4,20],nid:[3,16],rais:10,enable_dc:8,ns3_wrapper:6,ns3dceapplic:[12,1,21],netnswrapp:[12,21],redefin:10,scenario:10,inherit:10,client:[6,1,9,20,16,4],get_slice_vnet_sys_tag:9,thi:[5,6,1,9,10,20,16,4],install_depend:1,tcp_l4protocol:[12,21,6],protocol:4,linuxns3dceappl:8,ns3baseipv4l3protocol:[11,6],initiate_connect:[8,1],yet:[16,4],expos:10,character:10,save:[10,16,1],adress:4,noop_funct:4,mayb:16,preserv:1,ns3threelogdistancepropagationlossmodel:11,ns3ccncatdceappl:[8,12,1,21],background:[16,1],dce_vers:8,measur:[10,1],daemon:1,specif:[10,1,4],manual:1,fail_discoveri:[4,9],ns3okumurahatapropagationlossmodel:11,dce_application_uuid:6,fedora_12:1,fedora_14:1,negat:9,interv:10,recv_msg:[20,6],intern:16,clean_experi:1,planetlabtun:9,set_provis:10,subclass:10,get_trac:10,ns3basefdnetdevic:[11,6],condit:10,localhost:1,start_multical:9,core:[],plu:16,ssh_config:16,ple:[16,9],plc:9,unregister_connect:10,peer:9,get_nod:9,guidgener:16,obj:16,tdiffsec:16,make_kei:16,simul:[8,5,6,10,2],timestamp2:16,timestamp1:16,produc:10,ns3basedceappl:[8,6],shell_escap:16,newuuid:[20,6],"float":10,encod:16,www:9,node_ip_annot:16,separet:1,often:4,ns3sixlowpannetdevic:11,wai:[16,1,4,9],support:[10,16,1,9],transform:10,avail:[10,1,19],ap_wifi_mac:[12,21,6],gil:10,tcpdump:[12,21],fork:1,matrix_propagation_loss_model:[12,21,6],medium:1,minstrel_wifi_manag:[12,21,6],form:10,forc:[10,16,1],run_hom:[8,1],raise_on_error:1,heap:10,"true":[10,16,1,4],flavour:9,attr:[0,6,8,1,10,20,4],set_with_condit:10,mtr:[12,21],maximum:10,mtu:1,ecxmlpars:23,tsformat:16,ns3nisterrorratemodel:11,fixed_rss_loss_model:[12,21,6],featur:16,netnsipv4rout:20,configure_ifac:4,get_resource_urn:16,diagnost:16,workerthread:16,exist:[1,19,10,9,16,4],check:[1,19,10,9,16,4],from_typ:23,verify_connect:[8,1,19],steady_state_random_waypoint_mobility_model:[12,21,6],ns3baseicmpv4l4protocol:[11,6],when:[10,16,1,4],annotate_cn_nod:[3,22],test:[16,9],ns3node:[12,21],node:[10,3,12,21],traceattr:10,consid:10,to_typ:23,emu_get:20,longer:10,emu_net_devic:[12,21,6],create_hom:[16,1],exp_hom:1,time:[10,16,4,9,6],resource_urn:16,uan_channel:[12,21,6],annotate_node_ip:16,simple_net_devic:[12,21,6],concept:10,skip:10,consum:3,focus:4,create_and_enroll_top:4,fail_not_enough_nod:[4,9],remote_statu:16,netnsswitch:[12,21],decid:10,depend:[1,4,9],graph:[10,3,22,16],readabl:10,node_count:16,sourc:[0,13,5,7,6,1,19,9,2,10,16,23,11,8,3,14,4,22,20],string:[10,16,1,9],ns3receivelisterrormodel:11,wait_run:1,pl_pass:9,add_set_hook:[1,4],level:[10,16,20,4,6],get_rtyp:10,connection_app_hom:[1,19,9],upload_fil:1,filter_resourc:10,channeltofreq:4,receive_list_error_model:[12,21,6],ns3constantaccelerationmobilitymodel:11,arf_wifi_manag:[12,21,6],ns3ccnddceapplic:[8,12,1,21],port:[8,1,4,19,16],del_edge_annot:16,establish_connect:[8,1],repli:[16,20,6],current:[10,16,4,19],stformat:16,ovs_statu:19,deriv:10,udp_echo_serv:[12,21,6],old_valu:4,gener:[10,8,1,4,9],cara_wifi_manag:[12,21,6],satisfi:10,address:[10,8,4,16],use_deb:1,wait:[8,1,19,2,10,9],box:[16,4],check_mailbox:4,sfi_sm:16,plotter:[12,17],netgraph:[10,12,17],queue:[10,16,6],trial:1,yans_error_rate_model:[12,21,6],environn:4,linuxnetnscli:2,generate_topolog:16,prefer:10,backtick:16,instal:[1,9],mobil:6,ipv4l3protocol:[12,21,6],live:[5,1],criteria:10,msg:[10,8,1,16],scope:[10,1],ppid:[16,1],ns3steadystaterandomwaypointmobilitymodel:11,send_repli:[20,6],ip2:16,plexu:4,ip1:16,ip6:1,ip4:1,exp_id:[10,4],ccncat:[12,1,21],three_log_distance_propagation_loss_model:[12,21,6],uniqu:[10,16,4],cat:1,can:[10,16,1,4],deploy_with_condit:10,process_content_histori:3,purpos:10,get_resources_info:16,stream:10,ns3randomwalk2dmobilitymodel:11,eval_failur:10,topic:4,critic:10,abort:10,occur:[10,16,1],alwai:1,dump_head:[20,6],unimo:16,multipl:[10,16],annotate_edg:16,check_statu:[1,19],ns3radvd:11,ping:[12,15,18],purg:4,create_port:19,map:[16,9],stdin_funct:4,mac:1,nitlab:4,two_ray_ground_propagation_loss_model:[12,21,6],date:[10,16,4],data:[12,17],ns3arfwifimanag:11,vif_name_fil:9,stdin:[16,1,4],assign_p2p_ip:16,inform:[6,9,10,16,3,4],"switch":[10,20,19],block:[0,6,8,1,10,20,16,4],callabl:16,replace_path:[8,1,2],tty:[16,1,4],ns3wifiremotestationmanag:[12,21],still:[16,1],entiti:[10,13],jid:4,group:[10,16],polici:10,ns3wrappermessag:6,ns3propagationlossmodel:[12,21],platform:[10,16],mail:4,plcapi:[12,21],non:1,ns3randomdirection2dmobilitymodel:11,initi:[10,8,4],remove_resourc:10,select_base_class:6,verifi:8,now:4,list_error_model:[12,21,6],ns3ccnpokedceappl:[8,12,1,21],name:[0,6,8,1,9,2,10,20,16,3,4],separ:10,initiate_udp_connect:[1,19],x11:1,netnsclient:[12,1,21],ns3bulksendappl:11,compil:1,ns3rateerrormodel:11,udp_connect:1,replac:[8,1,2],continu:[10,16,1],newval:1,happen:[16,1],error_channel:[12,21,6],ns3constantspeedpropagationdelaymodel:11,subnet:16,ccn_produc:3,type_nam:[20,6],resource_hrn:16,cipher_kei:[8,1,19],oldval:1,factori:[8,16,6],resource_typ:10,ns3amrrwifimanag:11,urlpattern:[16,9],ns3errorchannelsixlow:11,get_start_tim:10,"byte":10,care:[10,16,1],ns3udptracecli:11,frequenc:4,synchron:1,turn:19,log_messag:[10,8,1,16],first:[10,16,1],oper:[10,20,6],do_fail:10,directli:[10,1,4],upload_command:1,onc:16,arrai:9,ns3cost231propagationlossmodel:11,parser:[12,15,18],error_channel_sixlow:[12,21,6],enable_dump:[20,6],custom:[4,9],open:16,size:10,given:[10,16,9],local_port:8,cumul:10,copi:[10,16,1],specifi:[10,16,9],open_socket:6,blacklist:[16,9],reserved_tim:10,ns3baseccndceappl:[14,6],add_edge_callback:10,ns3ccnrdceapplic:[8,12,1,21],tuntapfdlink:[12,1,21],sasl_mech:4,lkill:16,get_node_info:9,classmethod:[10,16,4,9],python_passfd_src:2,ressourc:10,were:10,tophat:16,ns3idealwifimanag:11,dump_to_script:[20,6],argument:[10,16,4,9],parallelrun:16,inform_failur:10,do_discov:[10,1,4,9],destroi:16,note:[1,9],ideal:16,omfnod:4,take:[10,16,1],advis:16,burst_error_model:[12,21,6],dump_get:[20,6],noth:[16,4],channel:[12,21],del_node_annot:16,begin:10,sure:16,trace:[12,17],normal:[10,1],track:[10,16],set_ec:10,ns3carawifimanag:11,set_glob:10,date2:16,pair:16,remove_packag:1,wilabtsfanod:4,ns3ping6:11,omf5:4,fdnetdevic:[7,8,6],later:[1,4],runtim:1,put_nowait:16,ns3basewifinetdevic:[11,6],start_with_condit:10,topologytyp:16,show:[10,16],get_failed_tim:10,netnsnod:[12,21],itu_r1411nlos_over_rooftop_propagation_loss_model:[12,21,6],xml:[10,16,23],onli:[1,19,10,9,16,4],explicitli:[10,1],state:[0,6,8,1,10,20,4],dict:[16,4],rspec_str:16,get:[6,8,1,9,2,10,19,16,4,20],repo:2,ssl:4,create_funct:4,ssh:[16,19,1,4,9],is_sourc:16,requir:[10,16,1],yield:10,upload_stdin:1,ns3lrwpannetdevic:11,make_control_path:16,where:[16,1,19],format_arg:[20,6],rexec:16,from_xml:23,msg_type:[8,6,20,2],fail_plapi:9,concern:4,date1:16,upload_cod:1,ns3baseappl:[11,6],parent:[10,16,4],ns3icmpv4l4protocol:[12,21],enumer:10,enough:10,ns3fibentrydceappl:[8,12,1,21],between:10,"import":[10,1],cmdlinearg:4,create_socket:20,amtogatewai:4,get_glob:10,ns3droptailqueu:11,tun:[12,21],remote_socket:[8,2],mani:[10,1],with_lock:1,mesh_wifi_interface_mac:[12,21,6],format_environ:1,ns3constantratewifimanag:11,colon:1,deploi:[10,1,4,19],binary_error_model:[12,21,6],get_ready_tim:10,ns3onoewifimanag:11,mark:[10,16],breath:16,omfresourc:4,state_time_attr:10,plapi:9,repons:13,newexp_funct:4,reschedul:10,do_provis:[6,19,1,13,10,9,4,20],ns3minstrelwifimanag:11,linuxns3dcefibentri:14,single_model_spectrum_channel:[12,21,6],prefixt:16,local_endpoint:19,linuxudptunnel:[8,1],gretunnel:[12,21],ns3multimodelspectrumchannel:11,experimentrunn:[10,5],set_hook:10,"case":[16,4],sfi_us:16,ovswitch:19,linuxrout:1,linuxns3dceccnpok:14,exec_run_hom:9,cast:23,invok:[10,8,6,20,2],invoc:[16,1,4],arp_l3protocol:[12,21,6],ccnapplic:[12,1,21],virtual_net_devic:[12,21,6],add_slice_nod:9,stdout:[16,1],metric:10,destin:[16,1,4],lr_wpan_net_devic:[12,21,6],ns3yanswifiphi:11,initialize_work:16,rmatcher:[12,17],dce_src_loc:8,same:[1,13,10,9,16,4],binari:1,ns3rraawifimanag:11,finish:[16,1,4],evaluate_convergence_callback:10,dump_stop:6,escape_quot:4,driver:5,check_sliver_ov:19,capabl:10,ns3bursterrormodel:11,finish_multical:9,ready_tim:10,ns3csmachannel:11,execute_deploy_command:1,load_content_histori:3,ccn:[12,15,18],disassoci:10,rpmfunc:[12,21],linuxccnd:0,manifold:16,execut:[12,17],allowed_typ:6,failed_tim:10,kill:[16,1,4],linuxccnr:0,get_slic:9,linuxccnp:0,flavor:1,struct:9,get_resources_hrn:16,except:1,param:[10,16,9],get_slice_tag:9,forward_x11:[16,1,4],newexp:4,ns3errornetdevic:11,drop_tail_queu:[12,21,6],read:[10,1],tid:[10,6],dbase:16,xmpp_root:4,get_frequ:4,delayed_except:16,integ:[10,1],server:[16,1,4,19],red_queu:[12,21,6],either:[10,16,1,4],appid:4,output:[16,1],manag:[10,5,16],is_valid_valu:10,format_kwarg:[20,6],ns3netdevic:[12,21],constant_speed_propagation_delay_model:[12,21,6],adequ:10,ns3wifiphi:[12,21],planetlabovsswitch:19,slice:[16,4,9],confirm:4,linuxns3simul:8,set_target:16,level_nam:4,exit:[10,1,4],nodefamili:9,linuxchannel:1,tapnod:8,do_stop:[0,6,8,1,9,2,10,20,4],add_resource_to_slice_batch:16,is_target:16,timeout:16,share_dir:1,logs_dir:[3,22],"throw":1,src:[1,4,2],select_random_sourc:16,central:16,netnsipv4address:[12,21],register_connect:10,establish_udp_connect:[1,19],shra:4,omfchannel:4,unregist:4,remove_packages_command:1,constant_rate_wifi_manag:[12,21,6],stare:16,log:[10,3,4,16],area:9,alias_funct:4,overwrit:1,start:[6,8,1,19,2,10,16,4],interfac:[10,12,21],rmdir:1,iff_tap:1,tupl:16,recv_fd:6,friis_propagation_loss_model:[12,21,6],netnsinterfac:[12,21],possibl:[10,1,4,19],"default":[10,16,4,9],uid:4,creat:[6,8,1,9,2,10,19,16,4,20],certain:10,file:[8,1,9,10,16,3,4,22],planetlabvrout:9,orient:[],field:[16,9],valid:[10,16],nakagami_propagation_loss_model:[12,21,6],you:[16,1,4],architectur:4,registri:9,python_unshare_src:2,ns3baseerrorratemodel:[11,6],dump_invok:[20,6],remote_kil:16,linuxinterfac:1,directori:[10,16,1,13],release_funct:4,wifi:4,descript:10,set_stat:10,escap:[8,1,16,2],bulk_send_appl:[12,21,6],represent:[10,16],all:[10,12,21],remove_resource_from_slic:16,do_connect:10,ns3itur1411lospropagationlossmodel:11,check_error:1,code:[10,5,1,16,8],follow:[10,1,9],scp:16,edg:16,get_node_flavour:9,template_attribut:6,those:[10,1],yans_wifi_channel:[12,21,6],ccnping:[12,1,21],global:[10,9],delete_slice_nod:9,noread:10,fals:[6,1,10,20,16,3,4],sshfunc:[12,17],vif_typ:1,util:[10,12,17,4],clientxmpp:4,load_ns3_modul:6,failur:10,jakes_propagation_loss_model:[12,21,6],nepi_hom:1,list:[7,8,1,9,10,16,4],ec_failur:10,emul:[5,20,2],stderr:[16,1],node1:8,node2:8,ns3wifinetdevic:[12,21],dump_shutdown:[20,6],omf_api_factori:[12,21],sync:16,design:10,pass:[10,16],fail_node_not_avail:[4,9],socket_nam:[8,6,20,2],brief:1,make_server_key_arg:16,configure_funct:4,delet:[16,1,4,19],ns3pipechanel:[12,21],version:[0,4,16,14],"public":16,is_finish:6,full:[10,4],exit_funct:4,send_stdin:4,ns3udpechoserv:11,bin_dir:1,dump_set:[20,6],modifi:10,valu:[6,1,10,20,16,4,23],optionn:9,search:[5,16],ecstat:10,ns3ccndceapplic:[8,12,1,21],unenroll_top:4,ns3pointtopointnetdevic:11,action:10,messagehandl:4,clone_command:2,six_low_pan_net_devic:[12,21,6],rraa_wifi_manag:[12,21,6],compute_mean:16,filenam:[3,1,22,8],establish:8,regist:[10,4],two:[10,1,6],taken:10,more:16,desir:[16,1,4,19],oh_buildings_propagation_loss_model:[12,21,6],ns3wrapperdebug:6,flag:[10,16],particular:16,known:10,set_valu:10,frcp_inform:4,none:[6,8,1,9,2,10,16,4],endpoint:[7,8,1,19],sincron:9,remote_spawn:16,dev:16,histori:3,remain:1,openssh:16,get_slice_id:9,share:[1,4,9],templat:10,ecplott:16,minimum:10,max_run:10,ns3pointtopointchannel:11,interconnect:[7,8,10,6],gwuser:16,procstatu:16,anoth:[10,1],ns3packetsink:11,random_waypoint_mobility_model:[12,21,6],ns3gaussmarkovmobilitymodel:11,ns3randompropagationlossmodel:11,isn:16,resourc:[12,17],cost231propagation_loss_model:[12,21,6],format_valu:[20,6],ns3udpechocli:11,associ:[10,13],rspawn:16,"short":1,connection_run_hom:[1,19,9],caus:16,callback:10,help:10,xmpp:4,vif_type_flag:1,through:[10,4],ns3csmanetdevic:11,paramet:[19,1,13,10,9,16,4],itu_r1411los_propagation_loss_model:[12,21,6],get_valu:10,pend:10,getpid:1,bypass:16,netnsnodeinterfac:[12,21],omf_client:[12,21],"return":[7,8,1,9,10,19,16,3,4],timestamp:[10,4],planetlabsfanod:9,resource_manager_gener:[12,21],framework:16,ns3adhocwifimac:11,detach:1,set_sourc:16,gethostbynam:16,dceapplic:6,ns3ohbuildingspropagationlossmodel:11,sfaapifactori:16,sock_nam:1,wait_deploi:10,fulli:9,lib_dir:1,load_configur:1,ns3basechannel:[11,6],realli:1,connect:[6,1,19,10,20,16,4],handle_messag:[20,6],event:4,provision_tim:10,item:4,enroll_host:4,publish:4,lstatu:16,print:19,foreground:1,qualifi:9,proxi:9,random_propagation_delay_model:[12,21,6],ns3onoffappl:11,reason:10,base:[0,6,7,8,1,19,9,2,10,23,13,16,11,14,4,20],clazznam:[20,6],put:[16,4],bash:1,planetlabns3fdudptunnel:7,thread:[10,16,4,9,6],launch:1,retriv:1,edge_annot:16,reserve_host:9,assign:[10,16,19],wait_finish:10,number:[10,8,4,16],xmppp:4,done:[10,16],do_start:[0,6,8,1,9,2,10,20,4],jabber:4,baseomfcli:4,differ:[10,16,1,4],script:1,interact:[10,1],linuxns3dceccnr:14,construct:[10,16,20,6],gauss_markov_mobility_model:[12,21,6],linuxdcep:8,linuxns3dceccncat:14,linuxns3dceccnd:14,store:[10,16,1],option:[16,1,9],relationship:10,get_slice_nod:9,part:[10,1],pars:[3,16],remot:[8,1,16,2],remov:[10,16,1],local_p:9,random_walk2d_mobility_model:[12,21,6],bridg:19,str:[10,16,4,9,23],expid:4,comput:[10,3,16],set_releas:10,omfwifiinterfac:4,packag:17,netnsserv:[12,21],"null":16,ns_log:6,annotate_nod:16,lib:1,self:[10,1],also:[16,1],without:[16,4],build:[16,1,4],vif_nam:9,distribut:10,get_resource_typ:10,planetlab:[10,12,21],previou:16,reach:10,ns3rout:[12,21],stdin_hook:4,node_id:[9,6],app_hom:[8,1],ns3noncommunicatingnetdevic:11,parse_ping_log:3,loopback_net_devic:[12,21,6],exp:1,execfunc:[12,17],linuxnp:1,netnswrapperdebug:20,debfunc:[12,21],heapq:10,ns3wifimac:[12,21],session:[16,4],networkx:16,ns3basewifichannel:[11,6],find:10,access:10,wifi_net_devic:[12,21,6],quer:16,evaluate_normal_converg:10,random_direction2d_mobility_model:[12,21,6],unus:4,express:[10,16],nativ:9,configure_on_omf5:4,configure_on_omf6:4,aarfcd_wifi_manag:[12,21,6],ns3icmpv6l4protocol:11,iff_tun:1,ns3basepropagationlossmodel:[11,6],netnsemul:[12,1,21],common:[20,4,6],set_start:10,planetlabtap:9,arp:6,linuxtunnel:1,locali:16,get_endpoint:[7,8,1],point_to_point_remote_channel:[12,21,6],see:16,linuxccnappl:0,arg:[6,8,1,13,2,10,19,16,4,20],reserv:[10,16,9],resourceact:10,ns3udpclient:11,reus:16,fibentri:[12,1,21],subscript:4,experi:[5,1,13,10,19,16,4],xmppclient:4,valid_connect:[0,8,1,19,9,2,10,13,4],numer:[10,9],to_xml:23,network_typ:9,tnow:16,ecseri:16,ns3simplenetdevic:11,install_packag:1,run_dir:10,clsinit:10,load:[10,16],run_id:10,instanti:10,schedul:[12,17],do_reserv:10,home_dir:1,linuxtracerout:1,shutdown:[10,8,6,20,2],linux:[10,12,21],backend:16,guid1:10,guid2:10,adhoc_wifi_mac:[12,21,6],devic:[7,8,1,9,6],empti:16,find_box:16,netnsappl:[12,21],ns3basewifiphi:[11,6],linuxns3ccndceappl:14,slice_id_or_nam:9,imag:[4,9],rspec:16,is_control:3,func:[10,16],blacklist_host:9,ns3jakespropagationlossmodel:11,look:[10,16],batch:16,"while":[10,1],behavior:[10,1,4],error:[10,16,1,19],python_passfd_repo:2,readi:[10,4],omf5api:4,origin:4,netnsbas:[12,21],itself:19,manifoldapifactori:16,bwlimit:[8,1,19],get_resources_by_typ:10,decor:10,fedora:1,belong:10,resolve_hostnam:16,sliver:[16,19],ns3tcpl4protocol:11,content_nam:3,rcopi:16,moment:[10,4],temporari:16,user:[10,16,1,4,9],lgetpid:16,find_hom:1,implement:[10,4],subpackag:17,openssh_has_persist:16,travers:16,task:[10,16,1],replace_arg:[20,6],older:16,wait_vif_nam:9,explan:1,ns3wrapper_debug:[12,21],app_id:4,udptest:[12,21],planetlabnod:9,close_socket:6,enrollkei:4,linuxccnpingserv:0,"0x7f0290310f90":6,input:[16,1],point_to_point_channel:[12,21,6],modul:17,bin:1,is_run:6,format:[10,16,1],submodul:[12,15,17,18],tap_bridg:[12,21,6],exp_dir:[10,1],ccn_client_lock:6,semi:1,dce_repo:8,signal:16,upload_extra_sourc:[8,2],elaps:10,collect:[10,22,13],"boolean":[10,19,4,9],frcp_creat:4,has_attribut:10,load_ns3_librari:6,plc_flavour:9,creation:[16,4],some:[16,9],back:4,failure_level:10,unspecifi:9,sampl:[10,16],ns3ltesimplenetdevic:11,ns3simplechannel:11,per:16,prop:4,retri:[16,1,4],reproduc:1,machin:10,object:[6,9,10,20,16,4,23],run:[10,16,1,4,19],has_flag:10,ping6:[12,21,6],gre_connect:[1,9],sfi_registri:16,wait_all_readi:10,from:[10,3,1,4,16],get_release_tim:10,send_msg:[8,2],constraint:16,private_kei:16,idn:16,dump_start:6,ns3kun2600mhzpropagationlossmodel:11,exitcod:1,pythonpath:1,pldistro:9,hrn:[16,4],all_tag:16,devnam:1,nowrit:10,omf6api:4,sock:6,"long":1,set_fail:10,includ:9,forward:1,compute_metric_callback:10,ns3hierarchicalmobilitymodel:11,ns3uanchannel:11,atom:10,line:[16,1],ns3:[12,1,21],info:[16,1,4],cid:4,uth:4,nid1:[16,22],planet:9,set_hook_mtu:1,similar:1,frcp_releas:4,set_state_tim:10,msg_id:4,ns3basequeu:[11,6],doesn:[16,4],repres:[10,16,1,4],lspawn:16,retract:4,filenotfound:1,failtrap:10,sfarspec_proc:[12,17],clean:[1,4],eintr_retri:16,fdnode:8,meaning:[10,4,19],rm_failur:10,linuxns3dceccnpeek:14,frcp_request:4,typeid:6,ns3wifichannel:[12,21],guids1:10,guids2:10,wait_fil:[8,1],exact_tag:16,queri:[10,16],release_api:4,node_annot:16,maxthread:16,is_rm_inst:10,set_hook_up:1,ns3binaryerrormodel:11,get_node_tag:9,send:[16,4],noop:4,sent:4,vlc:4,ns3_repo:8,tri:16,on_off_appl:[12,21,6],do_disconnect:10,myresourcemanag:10,refer:16,ns3basenod:[11,6],check_state_connect:[8,1],ecodefil:1,ns3itur1411nlosoverrooftoppropagationlossmodel:11,unblacklist_host:9,download:1,aloha_noack_net_devic:[12,21,6],pl_ptn:9,index:[10,5,4],resourcest:10,compute_delay_m:16,cell:4,experiment:10,ns3_get:6,icmpv6l4protocol:[12,21,6],get_discover_tim:10,whatev:16,"enum":10,"0x7f028fc193b0":4,vif_prefix:1,linuxns3fdudptunnel:[7,8],ubuntu:1,becom:4,sinc:[10,1,4],host:[5,1,9,10,16,4],corruptfil:1,wait_guid:10,converg:10,chang:[10,4],control:[10,19,1,4,13],set_reserv:10,app:1,bridge_net_devic:[12,21,6],gatewai:4,api:[5,4,9,16],statfunc:[12,17],hierarchical_mobility_model:[12,21,6],rclass:10,commun:4,logger_compon:16,ns3meshpointdevic:11,doubl:10,next:[10,16],ascii_helper_uuid:6,constant_velocity_mobility_model:[12,21,6],usr:1,check_deploi:4,mask4:1,enroll_top:4,mask6:1,comparison:9,subscriber_station_net_devic:[12,21,6],fedora_8:1,agent:16,ns3singlemodelspectrumchannel:11,upload_binari:1,retriev:[10,16,1,9],install_packages_command:1,tunnel:[12,21],alia:4,txqueuelen:[8,1,19],unenrol:4,annot:3,get_resource_info:16,omfapifactori:4,ns3alohanoacknetdevic:11,get_task:10,ns3errorratemodel:[12,21],tap:[12,21],process:[12,18],lock:[4,9,6],sudo:[16,1,4],trace_filepath:1,tag:[12,17],ns3arpl3protocol:[12,21],serial:[10,12,17],dce_manager_uuid:6,delai:[10,22],ccnpoke:[12,1,21],publicid:16,filepath:[10,16],ns3emunetdevic:11,plcapifactori:9,linuxccnpeek:0,instead:[10,16,1,4],linuxfibentri:0,stop_tim:10,overridden:[10,9],remote_check_pid:16,physic:10,alloc:16,non_communicating_net_devic:[12,21,6],loglevel:[20,6],ns3virtualnetdevic:11,element:[10,4],temp:[16,1],allow:[1,19,10,9,16,4],omf6pars:4,ns3basewifiremotestationmanag:[11,6],get_stop_tim:10,planelab:9,trace_en:10,add_edg:16,remote_endpoint:[8,1,19,9],device_helper_uuid:6,nist_error_rate_model:[12,21,6],ccnpingserv:[12,1,21],local_dir:10,populate_factori:10,therefor:10,python:[10,1],python_unshare_vers:2,ns3ocbwifimac:11,ns3aarfwifimanag:11,run_experi:10,rstatu:16,testbedtogatewai:4,get_connect:10,mode:1,wait_tim:10,chunk:10,udp_client:[12,21,6],special:[8,1,9,2,16,4],out:[16,1],variabl:[1,4],python_passfd_vers:2,install_rpmfusion_command:1,linuxgretunnel:1,develop:[],ns3errorchannel:11,identifi:[10,9],suitabl:[4,9],rel:[10,16],statist:10,ns3stawifimac:11,linuxtap:[1,9],ips2nid:[3,22],ns3udpserv:11,constant_position_mobility_model:[12,21,6],dictionari:[10,3,4],releas:[10,16,19,4,9],wilabt_nod:[12,21],xmlencod:23,has_chang:10,could:10,keep:[10,1],heappush:10,not_start:16,known_host:16,lexec:16,netnsrout:[12,21],python_unshare_repo:2,dump_content_histori:3,mai:9,set:[6,8,9,2,10,19,16,4,20],v4ping:[12,21,6],ccndlog:3,mkdir:[16,1],system:[4,9],wrapper:20,attach:[16,1],termin:[10,1],max_depth:16,get_interfac:9,udp:1,shell:[8,1,2],register_condit:10,netnswrapper_debug:[12,21],failurelevel:10,cpython:10,ns3base:[12,21],structur:1,check_output:1,amrr_wifi_manag:[12,21,6],sens:10,dce_help:8,enroll_funct:4,start_tim:10,kun2600mhz_propagation_loss_model:[12,21,6],session_kei:9,correspond:4,linuxnetnsemul:2,have:[10,16,1,6],close:19,need:[10,16,1,4,19],ns3basewifimac:[11,6],binary_error_sixlow_model:[12,21,6],emu_set:20,mcapi:9,rout:[12,21],error_net_devic:[12,21,6],do_configur:10,which:[10,16,1,4,9],interface_id_or_ip:9,instanci:[16,4,9],singl:[10,16,1],create_api:[4,9],unless:16,get_api:[16,4,9],deploy:[10,9],clase:10,discov:[10,4,9],cipher:[8,1,19],node_tag_id:9,sfi:[16,4,9],"class":[0,6,8,12,1,13,2,10,20,14,21],sfa:[16,4,9],build_sfa_rspec:16,ns3ipv4l3protocol:[12,21],url:[16,9],urn:16,gather:[1,4],request:[16,4],set_readi:10,pipe:[16,1,6],pidfil:[16,1],determin:16,text:[10,1],verbos:16,waypoint_mobility_model:[12,21,6],ccnpeek:[12,1,21],get_session_kei:16,redirect:[16,1],upload_librari:1,locat:16,should:[10,16,20,9,6],add_nod:16,wait_result:8,local:[10,16,1,13,9],create_bridg:19,ns3randomwaypointmobilitymodel:11,base_station_net_devic:[12,21,6],wait_remote_socket:[8,2],autom:1,ns3meshwifiinterfacemac:11,enabl:[10,20,6],ns3basepipechannel:6,lala:1,whether:[10,16,1],contain:[10,16,1,9],script_path:[20,6],view:9,node_id_or_hostnam:9,fdudptunnel:[12,1,21],planetlabtuntapfdlink:7,usr_dir:1,make_uuid:[20,6],statu:[10,16,1,19],extend:10,correctli:[4,9],ns3bridgenetdevic:11,pattern:9,inorm:22,written:4,ns3queue:[12,21],ns3v4ping:11,kei:16,update_slic:9,entir:16,disconnect:4,experimentcontrol:[5,1,19,10,13,4],add_resource_to_slic:16,rtype:[10,16,4],ccn_consum:3,messages_5_4:[12,21],plugin_config:4,tracerout:[12,21,22],etc:[10,16,1,4],instanc:[10,16,4,9],sigterm:16,rexitcod:1,complementari:[],arriv:10,respect:1,admin:9,rgetpid:16,quit:[10,16],resourcegatewai:4,compon:10,immedi:1,radvd:[12,21,6],icmpv4l4protocol:[12,21,6],presenc:4,assert:4,"0x7f028fc19a70":9,nping:[12,21],simple_channel:[12,21,6],togeth:16,present:5,replic:10,multi:1,plain:[1,9],remove_all_from_slic:16,defin:[10,4,9],sformat:16,eintr:16,get_attribut:10,ns3matrixpropagationlossmodel:11,ns3hybridbuildingspropagationlossmodel:11,site:16,request_funct:4,linuxccncont:0,clean_process:1,handl:[10,4],slicenam:[16,9],ns3dsrdsrrout:11,ns3waypointmobilitymodel:11,http:[16,1,9],hostnam:[16,4,9],rkill:16,upon:[10,9],discover_tim:10,phy:6,ns3pointtopointremotechannel:11,execute_funct:4,wthat:19,netns_repo:2,linuxudptest:1,well:[],ofr:4,command:[6,8,1,9,2,20,16,4],resourcefactori:10,usual:[10,16],less:10,vrout:[12,21],obtain:10,dump_creat:[20,6],add_node_callback:10,packet_sink:[12,21,6],annotate_cn_graph:[3,22],web:[16,9],ns3redqueu:11,point:16,init_mailbox:4,add:[9,10,16,3,4,22],is_al:1,stabsformat:16,logger:[6,12,10,20,17,4],match:[10,16,9],xmlrpc:9,dest:16,handle_omf_messag:4,ccncontent:[12,1,21],testb:[10,5,4],know:1,password:[16,4,9],recurs:16,like:[16,9],ns3nakagamipropagationlossmodel:11,necessari:[10,16,1],failuremanag:10,page:5,pygccxml_vers:8,lcopi:16,captur:16,nid2:16,rvqueue:16,"export":1,ns3rangepropagationlossmodel:11,flush:[8,6,20,2],home:[16,1],ilabt:4,librari:[16,1,4],rate_error_model:[12,21,6],node_id_or_nam:9,wilab2:4,leas:16,ipv4:6,sequenc:9,linuxtuntapfdlink:[7,8],ns3propagationdelaymodel:[12,21],dce:5,usag:1,omfclient:4,offset:[0,6,8,1,10,20,4],yyyymmddhhmmssffff:16,about:[10,9],actual:[8,1,2],socket:[8,2],wilabt:[16,4],run_and_wait:1,constant_acceleration_mobility_model:[12,21,6],automat:[10,1],guard:4,check_start:4,ns3yanswifichannel:11,imind:4,aarf_wifi_manag:[12,21,6],sfi_auth:16,ns3basepropagationdelaymodel:[11,6],"function":[10,16,1,4,9],ns3yanserrorratemodel:11,subscrib:4,lalal:1,ns3client:[12,1,21],uninstal:1,inlin:1,count:3,made:[10,1],in_foreground:1,reschedule_delai:10,resourcemanag:[5,6,1,13,10,20,4],asynchron:16,topo_typ:16,limit:16,template_trac:6,process_content_history_log:3,otherwis:10,problem:4,ns3lteuenetdevic:11,plugin_whitelist:4,evalu:10,ns3logdistancepropagationlossmodel:11,"int":[19,1,13,10,9,16,4],mask:16,dure:[10,1,19],tdiff:16,bridge_channel:[12,21,6],inf:4,ing:16,detail:[10,9],virtual:10,new_valu:4,node_hom:1,other:[10,5,1],bool:[10,16],branch:16,varieti:10,is_start:6,repeat:10,star:16,heapschedul:10,shfile:1,replace_kwarg:[20,6],ns3baseerrormodel:[11,6],linuxmtr:1,omf_5:4,debian:1,annotate_edge_net:16,reliabl:1,match_tag:16,controlpersist:16},objtypes:{"0":"py:module","1":"py:method","2":"py:function","3":"py:class","4":"py:attribute","5":"py:classmethod"},objnames:{"0":["py","module","Python module"],"1":["py","method","Python method"],"2":["py","function","Python function"],"3":["py","class","Python class"],"4":["py","attribute","Python attribute"],"5":["py","classmethod","Python class method"]},filenames:["_layout/nepi.resources.linux.ccn","_layout/nepi.resources.linux","_layout/nepi.resources.linux.netns","_layout/nepi.data.processing.ccn","_layout/nepi.resources.omf","index","_layout/nepi.resources.ns3","_layout/nepi.resources.planetlab.ns3","_layout/nepi.resources.linux.ns3","_layout/nepi.resources.planetlab","_layout/nepi.execution","_layout/nepi.resources.ns3.classes","_layout/nepi","_layout/nepi.resources.all","_layout/nepi.resources.linux.ns3.ccn","_layout/nepi.data.processing","_layout/nepi.util","_layout/modules","_layout/nepi.data","_layout/nepi.resources.planetlab.openvswitch","_layout/nepi.resources.netns","_layout/nepi.resources","_layout/nepi.data.processing.ping","_layout/nepi.util.parsers"],titles:["nepi.resources.linux.ccn package","nepi.resources.linux package","nepi.resources.linux.netns package","nepi.data.processing.ccn package","nepi.resources.omf package","NEPI modules","nepi.resources.ns3 package","nepi.resources.planetlab.ns3 package","nepi.resources.linux.ns3 package","nepi.resources.planetlab package","nepi.execution package","nepi.resources.ns3.classes package","nepi package","nepi.resources.all package","nepi.resources.linux.ns3.ccn package","nepi.data.processing package","nepi.util package","nepi","nepi.data package","nepi.resources.planetlab.openvswitch package","nepi.resources.netns package","nepi.resources package","nepi.data.processing.ping package","nepi.util.parsers package"],objects:{"":{nepi:[12,0,0,"-"]},"nepi.resources.ns3.classes.hierarchical_mobility_model":{NS3HierarchicalMobilityModel:[11,3,1,""]},"nepi.resources.linux.rpmfuncs":{install_rpmfusion_command:[1,2,1,""],remove_packages_command:[1,2,1,""],install_packages_command:[1,2,1,""]},"nepi.resources.netns.netnsswitch":{NetNSSwitch:[20,3,1,""]},"nepi.resources.linux.route":{LinuxRoute:[1,3,1,""]},"nepi.resources.ns3.classes.matrix_propagation_loss_model":{NS3MatrixPropagationLossModel:[11,3,1,""]},"nepi.util.parsers.xml_parser":{xmlencode:[23,2,1,""],to_type:[23,2,1,""],ECXMLParser:[23,3,1,""],from_type:[23,2,1,""],xmldecode:[23,2,1,""]},"nepi.resources.netns.netnswrapper.NetNSWrapper":{debuger:[20,4,1,""],invoke:[20,1,1,""],get:[20,1,1,""],get_object:[20,1,1,""],create:[20,1,1,""],replace_kwargs:[20,1,1,""],set:[20,1,1,""],make_uuid:[20,1,1,""],shutdown:[20,1,1,""],replace_args:[20,1,1,""],logger:[20,4,1,""]},"nepi.resources.netns.netnsserver.NetNSWrapperMessage":{SET:[20,4,1,""],INVOKE:[20,4,1,""],GET:[20,4,1,""],CREATE:[20,4,1,""],SHUTDOWN:[20,4,1,""],FLUSH:[20,4,1,""]},"nepi.resources.planetlab.plcapi.PLCAPI":{reserved:[9,1,1,""],get_slice_id:[9,1,1,""],delete_slice_node:[9,1,1,""],start_multicall:[9,1,1,""],get_node_tags:[9,1,1,""],api:[9,4,1,""],unblacklist_host:[9,1,1,""],get_slices:[9,1,1,""],get_slice_tags:[9,1,1,""],get_node_flavour:[9,1,1,""],mcapi:[9,4,1,""],peer_map:[9,4,1,""],test:[9,1,1,""],finish_multicall:[9,1,1,""],get_interfaces:[9,1,1,""],get_slice_nodes:[9,1,1,""],blacklist_host:[9,1,1,""],blacklisted:[9,1,1,""],unreserve_host:[9,1,1,""],get_node_info:[9,1,1,""],network_types:[9,4,1,""],get_slice_vnet_sys_tag:[9,1,1,""],release:[9,1,1,""],reserve_host:[9,1,1,""],get_nodes:[9,1,1,""],update_slice:[9,1,1,""],add_slice_nodes:[9,1,1,""]},"nepi.resources.ns3.ns3node.NS3BaseNode":{arp:[6,4,1,""],mobility:[6,4,1,""],devices:[6,4,1,""],simulation:[6,4,1,""],node_id:[6,4,1,""],ipv4:[6,4,1,""],dceapplications:[6,4,1,""]},"nepi.util":{sfaapi:[16,0,0,"-"],netgraph:[16,0,0,"-"],rmatcher:[16,0,0,"-"],plotter:[16,0,0,"-"],manifoldapi:[16,0,0,"-"],sfarspec_proc:[16,0,0,"-"],statfuncs:[16,0,0,"-"],parsers:[23,0,0,"-"],environ:[16,0,0,"-"],execfuncs:[16,0,0,"-"],timefuncs:[16,0,0,"-"],logger:[16,0,0,"-"],guid:[16,0,0,"-"],parallel:[16,0,0,"-"],serializer:[16,0,0,"-"],sshfuncs:[16,0,0,"-"]},"nepi.resources.linux.ccn.ccncontent":{LinuxCCNContent:[0,3,1,""]},"nepi.resources.ns3.classes.bridge_net_device":{NS3BridgeNetDevice:[11,3,1,""]},"nepi.resources.linux.node.ExitCode":{CORRUPTFILE:[1,4,1,""],FILENOTFOUND:[1,4,1,""],OK:[1,4,1,""],ERROR:[1,4,1,""]},"nepi.resources.ns3.classes.arf_wifi_manager":{NS3ArfWifiManager:[11,3,1,""]},"nepi.resources.linux.mtr.LinuxMtr":{upload_start_command:[1,1,1,""],do_deploy:[1,1,1,""],valid_connection:[1,1,1,""],do_start:[1,1,1,""]},"nepi.resources.ns3.classes.packet_sink":{NS3PacketSink:[11,3,1,""]},"nepi.execution.trace.TraceAttr":{PATH:[10,4,1,""],ALL:[10,4,1,""],STREAM:[10,4,1,""],SIZE:[10,4,1,""]},"nepi.resources.netns.netnsnodeinterface.NetNSNodeInterface":{node:[20,4,1,""],"switch":[20,4,1,""],emulation:[20,4,1,""]},"nepi.resources.linux.application.LinuxApplication":{upload_files:[1,1,1,""],upload_code:[1,1,1,""],do_release:[1,1,1,""],pid:[1,4,1,""],trace_filepath:[1,1,1,""],do_start:[1,1,1,""],upload_libraries:[1,1,1,""],valid_connection:[1,1,1,""],upload_binaries:[1,1,1,""],replace_paths:[1,1,1,""],state:[1,4,1,""],run_home:[1,4,1,""],build:[1,1,1,""],do_stop:[1,1,1,""],upload_sources:[1,1,1,""],ppid:[1,4,1,""],node:[1,4,1,""],app_home:[1,4,1,""],trace:[1,1,1,""],execute_command:[1,1,1,""],do_provision:[1,1,1,""],install_dependencies:[1,1,1,""],do_deploy:[1,1,1,""],log_message:[1,1,1,""],in_foreground:[1,4,1,""],execute_deploy_command:[1,1,1,""],upload_stdin:[1,1,1,""],install:[1,1,1,""],upload_start_command:[1,1,1,""]},"nepi.resources.ns3.ns3dceapplication.NS3BaseDceApplication":{do_stop:[6,1,1,""],pid:[6,4,1,""],do_start:[6,1,1,""],trace:[6,1,1,""]},"nepi.resources.linux.ccn.ccnpoke":{LinuxCCNPoke:[0,3,1,""]},"nepi.resources.netns.netnsnode":{NetNSNode:[20,3,1,""]},"nepi.resources.ns3.classes.multi_model_spectrum_channel":{NS3MultiModelSpectrumChannel:[11,3,1,""]},"nepi.resources.linux.ccn.fibentry.LinuxFIBEntry":{node:[0,4,1,""],traceroute:[0,4,1,""],valid_connection:[0,1,1,""],trace:[0,1,1,""],ping:[0,4,1,""],ccnd:[0,4,1,""],do_deploy:[0,1,1,""],do_start:[0,1,1,""],upload_start_command:[0,1,1,""],do_stop:[0,1,1,""],configure:[0,1,1,""]},"nepi.data.processing.ping.parser":{annotate_cn_graph:[22,2,1,""],parse_file:[22,2,1,""],annotate_cn_node:[22,2,1,""]},"nepi.resources.ns3.ns3route.NS3Route":{node:[6,4,1,""]},"nepi.util.logger":{Logger:[16,3,1,""]},"nepi.resources.ns3.classes.radvd":{NS3Radvd:[11,3,1,""]},"nepi.resources.linux.tcpdump.LinuxTcpdump":{do_deploy:[1,1,1,""],valid_connection:[1,1,1,""]},"nepi.resources.netns.netnsroute.NetNSIPv4Route":{node:[20,4,1,""],emulation:[20,4,1,""]},"nepi.resources.ns3.classes.cost231propagation_loss_model":{NS3Cost231PropagationLossModel:[11,3,1,""]},"nepi.util.sshfuncs":{rspawn:[16,2,1,""],STDOUT:[16,3,1,""],log:[16,2,1,""],openssh_has_persist:[16,2,1,""],resolve_hostname:[16,2,1,""],rkill:[16,2,1,""],make_server_key_args:[16,2,1,""],gethostbyname:[16,2,1,""],shell_escape:[16,2,1,""],ProcStatus:[16,3,1,""],rexec:[16,2,1,""],eintr_retry:[16,2,1,""],make_control_path:[16,2,1,""],rcopy:[16,2,1,""],rgetpid:[16,2,1,""],rstatus:[16,2,1,""]},"nepi.resources.ns3.classes.subscriber_station_net_device":{NS3SubscriberStationNetDevice:[11,3,1,""]},"nepi.resources.linux.channel":{LinuxChannel:[1,3,1,""]},"nepi.resources.planetlab.ns3.fdudptunnel.PlanetlabNs3FdUdpTunnel":{get_endpoints:[7,1,1,""]},"nepi.resources.linux.traceroute.LinuxTraceroute":{upload_start_command:[1,1,1,""],do_deploy:[1,1,1,""],valid_connection:[1,1,1,""],do_start:[1,1,1,""]},"nepi.resources.linux.ccn.ccnpeek.LinuxCCNPeek":{do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.resources.linux.debfuncs":{remove_packages_command:[1,2,1,""],install_packages_command:[1,2,1,""]},"nepi.resources.ns3.classes.yans_wifi_phy":{NS3YansWifiPhy:[11,3,1,""]},"nepi.resources.linux.route.LinuxRoute":{node:[1,4,1,""],device:[1,4,1,""],do_deploy:[1,1,1,""],do_start:[1,1,1,""],upload_start_command:[1,1,1,""],do_stop:[1,1,1,""],upload_sources:[1,1,1,""]},"nepi.resources.netns.netnsserver":{get_options:[20,2,1,""],NetNSWrapperMessage:[20,3,1,""],run_server:[20,2,1,""],recv_msg:[20,2,1,""],create_socket:[20,2,1,""],handle_message:[20,2,1,""],send_reply:[20,2,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccndceapplication":{LinuxNS3CCNDceApplication:[14,3,1,""]},"nepi.resources.ns3.ns3errorratemodel.NS3BaseErrorRateModel":{node:[6,4,1,""],phy:[6,4,1,""]},"nepi.resources.omf.omf6_api.OMF6API":{frcp_inform:[4,1,1,""],unenroll_topic:[4,1,1,""],disconnect:[4,1,1,""],create_and_enroll_topic:[4,1,1,""],frcp_configure:[4,1,1,""],check_ready:[4,1,1,""],frcp_create:[4,1,1,""],frcp_release:[4,1,1,""],check_mailbox:[4,1,1,""],frcp_request:[4,1,1,""],enroll_topic:[4,1,1,""]},"nepi.resources.planetlab":{node:[9,0,0,"-"],ns3:[7,0,0,"-"],tap:[9,0,0,"-"],vroute:[9,0,0,"-"],sfa_node:[9,0,0,"-"],openvswitch:[19,0,0,"-"],tun:[9,0,0,"-"],plcapi:[9,0,0,"-"]},"nepi.resources.omf.channel.OMFChannel":{valid_connection:[4,1,1,""],get_frequency:[4,1,1,""],do_release:[4,1,1,""],do_deploy:[4,1,1,""],ChannelToFreq:[4,4,1,""],exp_id:[4,4,1,""]},"nepi.resources.netns.netnsapplication":{NetNSApplication:[20,3,1,""]},"nepi.resources.netns.netnsipv4address":{NetNSIPv4Address:[20,3,1,""]},"nepi.execution.resource.ResourceAction":{START:[10,4,1,""],STOP:[10,4,1,""],DEPLOY:[10,4,1,""]},"nepi.resources.planetlab.ns3.fdudptunnel":{PlanetlabNs3FdUdpTunnel:[7,3,1,""]},"nepi.util.serializer":{ECSerializer:[16,3,1,""],SFormats:[16,3,1,""]},"nepi.resources.netns.netnsclient.NetNSClient":{set:[20,1,1,""],invoke:[20,1,1,""],get:[20,1,1,""],create:[20,1,1,""],shutdown:[20,1,1,""],flush:[20,1,1,""]},"nepi.util.sshfuncs.ProcStatus":{NOT_STARTED:[16,4,1,""],RUNNING:[16,4,1,""],FINISHED:[16,4,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication":{LinuxNS3DceCCNR:[14,3,1,""]},"nepi.resources.ns3.classes.aarf_wifi_manager":{NS3AarfWifiManager:[11,3,1,""]},"nepi.resources.ns3.ns3ccndceapplication.NS3BaseCCNDceApplication":{ccn_client_lock:[6,4,1,""],ccn_client_helper_uuid:[6,4,1,""]},"nepi.resources.ns3.classes.csma_channel":{NS3CsmaChannel:[11,3,1,""]},"nepi.resources.ns3.classes.uan_channel":{NS3UanChannel:[11,3,1,""]},"nepi.resources.linux.ccn.ccnpeek":{LinuxCCNPeek:[0,3,1,""]},"nepi.execution.runner.ExperimentRunner":{evaluate_normal_convergence:[10,1,1,""],run:[10,1,1,""],run_experiment:[10,1,1,""]},"nepi.resources.ns3.ns3icmpv4l4protocol":{NS3BaseIcmpv4L4Protocol:[6,3,1,""]},"nepi.resources.ns3.ns3channel":{NS3BaseChannel:[6,3,1,""]},"nepi.resources.ns3.ns3base":{NS3Base:[6,3,1,""]},"nepi.resources.omf.interface":{OMFWifiInterface:[4,3,1,""]},"nepi.resources.ns3.classes.okumura_hata_propagation_loss_model":{NS3OkumuraHataPropagationLossModel:[11,3,1,""]},"nepi.resources.netns.netnswrapper_debug.NetNSWrapperDebuger":{format_kwargs:[20,1,1,""],dump_factory:[20,1,1,""],dump_create:[20,1,1,""],dump_shutdown:[20,1,1,""],dump_to_script:[20,1,1,""],enabled:[20,4,1,""],dump_invoke:[20,1,1,""],format_value:[20,1,1,""],dump_header:[20,1,1,""],format_args:[20,1,1,""],script_path:[20,4,1,""],dump_set:[20,1,1,""],dump_get:[20,1,1,""]},"nepi.util.plotter.PFormats":{FIGURE:[16,4,1,""],DOT:[16,4,1,""]},"nepi.resources.ns3.classes.virtual_net_device":{NS3VirtualNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.ap_wifi_mac":{NS3ApWifiMac:[11,3,1,""]},"nepi.resources.omf.omf_client":{OMFClient:[4,3,1,""],BaseOMFClient:[4,3,1,""]},"nepi.util.statfuncs":{compute_mean:[16,2,1,""]},"nepi.util.manifoldapi.MANIFOLDAPIFactory":{make_key:[16,5,1,""],get_api:[16,5,1,""]},"nepi.execution.runner":{ExperimentRunner:[10,3,1,""]},"nepi.resources.linux.udptunnel.LinuxUdpTunnel":{initiate_connection:[1,1,1,""],verify_connection:[1,1,1,""],establish_connection:[1,1,1,""],log_message:[1,1,1,""],terminate_connection:[1,1,1,""],get_endpoints:[1,1,1,""],check_state_connection:[1,1,1,""]},"nepi.resources.ns3.classes.lte_enb_net_device":{NS3LteEnbNetDevice:[11,3,1,""]},"nepi.resources.omf.channel":{OMFChannel:[4,3,1,""]},"nepi.resources.linux.netns.netnsemulation.LinuxNetNSEmulation":{clone_command:[2,1,1,""],netns_src:[2,4,1,""],socket_name:[2,4,1,""],python_unshare_repo:[2,4,1,""],do_start:[2,1,1,""],valid_connection:[2,1,1,""],replace_paths:[2,1,1,""],python_unshare_version:[2,4,1,""],do_stop:[2,1,1,""],upload_sources:[2,1,1,""],do_release:[2,1,1,""],python_unshare_src:[2,4,1,""],wait_remote_socket:[2,1,1,""],python_passfd_version:[2,4,1,""],do_deploy:[2,1,1,""],netns_version:[2,4,1,""],remote_socket:[2,4,1,""],netns_repo:[2,4,1,""],upload_extra_sources:[2,1,1,""],python_passfd_src:[2,4,1,""],upload_start_command:[2,1,1,""],python_passfd_repo:[2,4,1,""]},"nepi.execution.resource.ResourceFactory":{create:[10,5,1,""],register_type:[10,5,1,""],resource_types:[10,5,1,""],get_resource_type:[10,5,1,""]},"nepi.util.timefuncs":{stabsformat:[16,2,1,""],compute_delay_ms:[16,2,1,""],tdiff:[16,2,1,""],tnow:[16,2,1,""],tsformat:[16,2,1,""],stformat:[16,2,1,""],tdiffsec:[16,2,1,""]},"nepi.execution.attribute.Types":{Integer:[10,4,1,""],Double:[10,4,1,""],Bool:[10,4,1,""],String:[10,4,1,""],Enumerate:[10,4,1,""]},"nepi.resources.omf.messages_5_4.MessageHandler":{enroll_function:[4,1,1,""],configure_function:[4,1,1,""],exit_function:[4,1,1,""],alias_function:[4,1,1,""],execute_function:[4,1,1,""],stdin_function:[4,1,1,""],log_function:[4,1,1,""],noop_function:[4,1,1,""],newexp_function:[4,1,1,""]},"nepi.resources.omf.messages_6":{MessageHandler:[4,3,1,""]},"nepi.resources.ns3.ns3queue.NS3BaseQueue":{device:[6,4,1,""],node:[6,4,1,""]},"nepi.resources.linux.gretunnel":{LinuxGRETunnel:[1,3,1,""]},"nepi.resources.ns3.classes.ocb_wifi_mac":{NS3OcbWifiMac:[11,3,1,""]},"nepi.execution.ec.FailureManager":{ec:[10,4,1,""],abort:[10,4,1,""],eval_failure:[10,1,1,""],set_ec_failure:[10,1,1,""],set_ec:[10,1,1,""]},"nepi.resources.omf.omf_api_factory.OMFAPIFactory":{lock:[4,4,1,""],create_api:[4,5,1,""],release_api:[4,5,1,""],get_api:[4,5,1,""]},"nepi.resources.ns3.ns3wifiremotestationmanager.NS3BaseWifiRemoteStationManager":{device:[6,4,1,""],node:[6,4,1,""]},"nepi.resources.ns3.ns3wifiphy":{NS3BaseWifiPhy:[6,3,1,""]},"nepi.resources.ns3.ns3arpl3protocol.NS3BaseArpL3Protocol":{node:[6,4,1,""]},"nepi.resources.planetlab.openvswitch.ovsport":{PlanetlabOVSPort:[19,3,1,""]},"nepi.data.processing.ccn":{parser:[3,0,0,"-"]},"nepi.resources.ns3.classes.log_distance_propagation_loss_model":{NS3LogDistancePropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.ns3fdnetdevice.NS3BaseFdNetDevice":{recv_fd:[6,1,1,""]},"nepi.resources.ns3.classes.udp_trace_client":{NS3UdpTraceClient:[11,3,1,""]},"nepi.resources.ns3.ns3wifiremotestationmanager":{NS3BaseWifiRemoteStationManager:[6,3,1,""]},"nepi.resources.ns3.classes.random_direction2d_mobility_model":{NS3RandomDirection2dMobilityModel:[11,3,1,""]},"nepi.resources.ns3.ns3wifichannel.NS3BaseWifiChannel":{phys:[6,4,1,""],simulation:[6,4,1,""]},"nepi.resources.ns3.classes.constant_velocity_mobility_model":{NS3ConstantVelocityMobilityModel:[11,3,1,""]},"nepi.resources.ns3.classes.three_log_distance_propagation_loss_model":{NS3ThreeLogDistancePropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.classes":{constant_rate_wifi_manager:[11,0,0,"-"],sta_wifi_mac:[11,0,0,"-"],waypoint_mobility_model:[11,0,0,"-"],ocb_wifi_mac:[11,0,0,"-"],dsrdsr_routing:[11,0,0,"-"],hybrid_buildings_propagation_loss_model:[11,0,0,"-"],packet_sink:[11,0,0,"-"],loopback_net_device:[11,0,0,"-"],itu_r1411los_propagation_loss_model:[11,0,0,"-"],nist_error_rate_model:[11,0,0,"-"],yans_wifi_channel:[11,0,0,"-"],point_to_point_channel:[11,0,0,"-"],random_direction2d_mobility_model:[11,0,0,"-"],lr_wpan_net_device:[11,0,0,"-"],udp_trace_client:[11,0,0,"-"],list_error_model:[11,0,0,"-"],bridge_net_device:[11,0,0,"-"],jakes_propagation_loss_model:[11,0,0,"-"],rraa_wifi_manager:[11,0,0,"-"],receive_list_error_model:[11,0,0,"-"],virtual_net_device:[11,0,0,"-"],minstrel_wifi_manager:[11,0,0,"-"],multi_model_spectrum_channel:[11,0,0,"-"],itu_r1411nlos_over_rooftop_propagation_loss_model:[11,0,0,"-"],lte_enb_net_device:[11,0,0,"-"],point_to_point_remote_channel:[11,0,0,"-"],binary_error_sixlow_model:[11,0,0,"-"],error_channel:[11,0,0,"-"],aloha_noack_net_device:[11,0,0,"-"],udp_l4protocol:[11,0,0,"-"],amrr_wifi_manager:[11,0,0,"-"],ideal_wifi_manager:[11,0,0,"-"],rate_error_model:[11,0,0,"-"],kun2600mhz_propagation_loss_model:[11,0,0,"-"],icmpv6l4protocol:[11,0,0,"-"],csma_net_device:[11,0,0,"-"],udp_echo_client:[11,0,0,"-"],constant_speed_propagation_delay_model:[11,0,0,"-"],drop_tail_queue:[11,0,0,"-"],random_propagation_delay_model:[11,0,0,"-"],ping6:[11,0,0,"-"],constant_position_mobility_model:[11,0,0,"-"],onoe_wifi_manager:[11,0,0,"-"],okumura_hata_propagation_loss_model:[11,0,0,"-"],bulk_send_application:[11,0,0,"-"],lte_simple_net_device:[11,0,0,"-"],yans_error_rate_model:[11,0,0,"-"],non_communicating_net_device:[11,0,0,"-"],red_queue:[11,0,0,"-"],mesh_wifi_interface_mac:[11,0,0,"-"],error_net_device:[11,0,0,"-"],aarfcd_wifi_manager:[11,0,0,"-"],v4ping:[11,0,0,"-"],binary_error_model:[11,0,0,"-"],emu_net_device:[11,0,0,"-"],hierarchical_mobility_model:[11,0,0,"-"],fd_net_device:[11,0,0,"-"],constant_acceleration_mobility_model:[11,0,0,"-"],gauss_markov_mobility_model:[11,0,0,"-"],ipv4l3protocol:[11,0,0,"-"],constant_velocity_mobility_model:[11,0,0,"-"],ap_wifi_mac:[11,0,0,"-"],simple_net_device:[11,0,0,"-"],csma_channel:[11,0,0,"-"],icmpv4l4protocol:[11,0,0,"-"],wifi_net_device:[11,0,0,"-"],oh_buildings_propagation_loss_model:[11,0,0,"-"],range_propagation_loss_model:[11,0,0,"-"],lte_ue_net_device:[11,0,0,"-"],yans_wifi_phy:[11,0,0,"-"],single_model_spectrum_channel:[11,0,0,"-"],mesh_point_device:[11,0,0,"-"],simple_channel:[11,0,0,"-"],arf_wifi_manager:[11,0,0,"-"],three_log_distance_propagation_loss_model:[11,0,0,"-"],friis_propagation_loss_model:[11,0,0,"-"],aarf_wifi_manager:[11,0,0,"-"],tap_bridge:[11,0,0,"-"],random_propagation_loss_model:[11,0,0,"-"],random_walk2d_mobility_model:[11,0,0,"-"],radvd:[11,0,0,"-"],six_low_pan_net_device:[11,0,0,"-"],on_off_application:[11,0,0,"-"],arp_l3protocol:[11,0,0,"-"],fixed_rss_loss_model:[11,0,0,"-"],adhoc_wifi_mac:[11,0,0,"-"],base_station_net_device:[11,0,0,"-"],log_distance_propagation_loss_model:[11,0,0,"-"],udp_echo_server:[11,0,0,"-"],udp_client:[11,0,0,"-"],steady_state_random_waypoint_mobility_model:[11,0,0,"-"],point_to_point_net_device:[11,0,0,"-"],tcp_l4protocol:[11,0,0,"-"],random_waypoint_mobility_model:[11,0,0,"-"],nakagami_propagation_loss_model:[11,0,0,"-"],burst_error_model:[11,0,0,"-"],subscriber_station_net_device:[11,0,0,"-"],error_channel_sixlow:[11,0,0,"-"],node:[11,0,0,"-"],cost231propagation_loss_model:[11,0,0,"-"],two_ray_ground_propagation_loss_model:[11,0,0,"-"],cara_wifi_manager:[11,0,0,"-"],matrix_propagation_loss_model:[11,0,0,"-"],udp_server:[11,0,0,"-"],bridge_channel:[11,0,0,"-"],uan_channel:[11,0,0,"-"]},"nepi.resources.planetlab.openvswitch.ovs":{PlanetlabOVSSwitch:[19,3,1,""]},"nepi.resources.netns.netnsapplication.NetNSApplication":{node:[20,4,1,""],state:[20,4,1,""],emulation:[20,4,1,""],do_start:[20,1,1,""]},"nepi.resources.ns3.ns3dceapplication":{NS3BaseDceApplication:[6,3,1,""]},"nepi.resources.linux.ccn.ccnping.LinuxCCNPing":{ccnpingserver:[0,4,1,""],valid_connection:[0,1,1,""],do_start:[0,1,1,""]},"nepi.resources.linux.netns":{netnsclient:[2,0,0,"-"],netnsemulation:[2,0,0,"-"]},"nepi.resources.ns3.classes.on_off_application":{NS3OnOffApplication:[11,3,1,""]},"nepi.resources.omf.omf5_api.OMF5API":{execute:[4,1,1,""],disconnect:[4,1,1,""],configure:[4,1,1,""],enroll_host:[4,1,1,""],exit:[4,1,1,""],send_stdin:[4,1,1,""],release:[4,1,1,""],"delete":[4,1,1,""]},"nepi.resources.ns3.classes.bridge_channel":{NS3BridgeChannel:[11,3,1,""]},"nepi.util.parallel.ParallelRun":{initialize_workers:[16,1,1,""],join:[16,1,1,""],sync:[16,1,1,""],start:[16,1,1,""],put_nowait:[16,1,1,""],put:[16,1,1,""],destroy:[16,1,1,""],empty:[16,1,1,""]},"nepi.resources.ns3.ns3icmpv4l4protocol.NS3BaseIcmpv4L4Protocol":{node:[6,4,1,""]},"nepi.resources.linux.ns3.ns3client":{LinuxNS3Client:[8,3,1,""]},"nepi.resources.ns3.classes.error_channel":{NS3ErrorChannel:[11,3,1,""]},"nepi.resources.ns3.ns3dcehelper":{NS3DceHelper:[6,3,1,""]},"nepi.resources.linux.ns3.ns3simulation":{LinuxNS3Simulation:[8,3,1,""]},"nepi.util.sfaapi":{SFAAPI:[16,3,1,""],SFAAPIFactory:[16,3,1,""]},"nepi.resources.ns3.classes.udp_server":{NS3UdpServer:[11,3,1,""]},"nepi.util.sfaapi.SFAAPIFactory":{make_key:[16,5,1,""],get_api:[16,5,1,""]},"nepi.resources.omf.omf6_parser":{OMF6Parser:[4,3,1,""]},"nepi.resources.netns.netnswrapper":{NetNSWrapper:[20,3,1,""]},"nepi.resources.ns3.classes.wifi_net_device":{NS3WifiNetDevice:[11,3,1,""]},"nepi.resources.all":{collector:[13,0,0,"-"]},"nepi.resources.ns3.classes.ideal_wifi_manager":{NS3IdealWifiManager:[11,3,1,""]},"nepi.resources.linux.netns.netnsemulation":{LinuxNetNSEmulation:[2,3,1,""]},"nepi.resources.ns3.classes.waypoint_mobility_model":{NS3WaypointMobilityModel:[11,3,1,""]},"nepi.util.sfarspec_proc":{SfaRSpecProcessing:[16,3,1,""]},"nepi.resources.omf.omf5_api":{OMF5API:[4,3,1,""]},"nepi.execution.trace":{TraceAttr:[10,3,1,""],Trace:[10,3,1,""]},"nepi.resources.ns3.classes.fixed_rss_loss_model":{NS3FixedRssLossModel:[11,3,1,""]},"nepi.resources.ns3.ns3wrapper":{NS3Wrapper:[6,3,1,""],load_ns3_module:[6,2,1,""],load_ns3_libraries:[6,2,1,""]},"nepi.resources.linux.ns3.fdudptunnel.LinuxNs3FdUdpTunnel":{establish_connection:[8,1,1,""],wait_file:[8,1,1,""],establish:[8,1,1,""],endpoint_node:[8,1,1,""],wait_local_port:[8,1,1,""],verify:[8,1,1,""],run_home:[8,1,1,""],endpoint1:[8,4,1,""],endpoint2:[8,4,1,""],pi:[8,4,1,""],check_state_connection:[8,1,1,""],app_home:[8,1,1,""],upload_sources:[8,1,1,""],verify_connection:[8,1,1,""],log_message:[8,1,1,""],wait_result:[8,1,1,""],initiate_connection:[8,1,1,""],initiate:[8,1,1,""],endpoint_mkdir:[8,1,1,""],node1:[8,4,1,""],node2:[8,4,1,""],terminate_connection:[8,1,1,""],get_endpoints:[8,1,1,""]},"nepi.resources.ns3.ns3client":{NS3Client:[6,3,1,""]},"nepi.resources.ns3.classes.gauss_markov_mobility_model":{NS3GaussMarkovMobilityModel:[11,3,1,""]},"nepi.resources.linux.ccn.ccnpingserver.LinuxCCNPingServer":{do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.resources.ns3.classes.minstrel_wifi_manager":{NS3MinstrelWifiManager:[11,3,1,""]},"nepi.util.execfuncs":{lcopy:[16,2,1,""],lkill:[16,2,1,""],lstatus:[16,2,1,""],lspawn:[16,2,1,""],lgetpid:[16,2,1,""],lexec:[16,2,1,""]},"nepi.resources.ns3.ns3application.NS3BaseApplication":{node:[6,4,1,""],do_stop:[6,1,1,""],state:[6,4,1,""],do_start:[6,1,1,""]},"nepi.execution.resource.ResourceManager":{do_fail:[10,1,1,""],do_configure:[10,1,1,""],set:[10,1,1,""],register_connection:[10,1,1,""],trace_enabled:[10,1,1,""],get_global:[10,5,1,""],do_connect:[10,1,1,""],do_release:[10,1,1,""],discover:[10,1,1,""],ec:[10,4,1,""],deploy_with_conditions:[10,1,1,""],do_discover:[10,1,1,""],set_global:[10,5,1,""],set_state:[10,1,1,""],set_stopped:[10,1,1,""],do_start:[10,1,1,""],is_rm_instance:[10,1,1,""],guid:[10,4,1,""],set_failed:[10,1,1,""],has_flag:[10,1,1,""],do_reserve:[10,1,1,""],stop_with_conditions:[10,1,1,""],has_changed:[10,1,1,""],valid_connection:[10,1,1,""],failed_time:[10,4,1,""],get:[10,1,1,""],unregister_connection:[10,1,1,""],discover_time:[10,4,1,""],set_state_time:[10,1,1,""],start:[10,1,1,""],state:[10,4,1,""],reserved_time:[10,4,1,""],has_attribute:[10,1,1,""],set_started:[10,1,1,""],set_provisioned:[10,1,1,""],get_rtype:[10,5,1,""],enable_trace:[10,1,1,""],set_discovered:[10,1,1,""],configure:[10,1,1,""],trace:[10,1,1,""],deploy:[10,1,1,""],stop:[10,1,1,""],start_time:[10,4,1,""],do_provision:[10,1,1,""],get_attribute:[10,5,1,""],stop_time:[10,4,1,""],connections:[10,4,1,""],set_with_conditions:[10,1,1,""],reschedule_delay:[10,4,1,""],do_deploy:[10,1,1,""],get_traces:[10,5,1,""],get_platform:[10,5,1,""],do_stop:[10,1,1,""],log_message:[10,1,1,""],register_condition:[10,1,1,""],provision:[10,1,1,""],provision_time:[10,4,1,""],unregister_condition:[10,1,1,""],get_connected:[10,1,1,""],start_with_conditions:[10,1,1,""],ready_time:[10,4,1,""],conditions:[10,4,1,""],set_reserved:[10,1,1,""],set_released:[10,1,1,""],release_time:[10,4,1,""],do_disconnect:[10,1,1,""],get_help:[10,5,1,""],release:[10,1,1,""],fail:[10,1,1,""],set_ready:[10,1,1,""],get_attributes:[10,5,1,""],reserve:[10,1,1,""]},"nepi.util.rmatcher":{find_boxes:[16,2,1,""],match_tags:[16,2,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccnddceapplication":{LinuxNS3DceCCND:[14,3,1,""]},"nepi.resources.ns3.ns3wrapper_debug.NS3WrapperDebuger":{format_kwargs:[6,1,1,""],dump_factory:[6,1,1,""],dump_invoke:[6,1,1,""],dump_shutdown:[6,1,1,""],dump_stop:[6,1,1,""],dump_to_script:[6,1,1,""],enabled:[6,4,1,""],dump_create:[6,1,1,""],format_value:[6,1,1,""],dump_header:[6,1,1,""],format_args:[6,1,1,""],dump_start:[6,1,1,""],script_path:[6,4,1,""],dump_set:[6,1,1,""],dump_get:[6,1,1,""]},"nepi.resources.ns3.ns3propagationdelaymodel":{NS3BasePropagationDelayModel:[6,3,1,""]},"nepi.resources.ns3.ns3mobilitymodel":{NS3BaseMobilityModel:[6,3,1,""]},"nepi.resources.ns3.classes.base_station_net_device":{NS3BaseStationNetDevice:[11,3,1,""]},"nepi.resources.ns3.ns3errorratemodel":{NS3BaseErrorRateModel:[6,3,1,""]},"nepi.resources":{all:[13,0,0,"-"],omf:[4,0,0,"-"],planetlab:[9,0,0,"-"],linux:[1,0,0,"-"],netns:[20,0,0,"-"],ns3:[6,0,0,"-"]},nepi:{util:[16,0,0,"-"],execution:[10,0,0,"-"],data:[18,0,0,"-"],resources:[21,0,0,"-"]},"nepi.resources.ns3.classes.ipv4l3protocol":{NS3Ipv4L3Protocol:[11,3,1,""]},"nepi.resources.ns3.classes.error_channel_sixlow":{NS3ErrorChannelSixlow:[11,3,1,""]},"nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model":{NS3SteadyStateRandomWaypointMobilityModel:[11,3,1,""]},"nepi.resources.linux":{node:[1,0,0,"-"],tap:[1,0,0,"-"],application:[1,0,0,"-"],mtr:[1,0,0,"-"],route:[1,0,0,"-"],ping:[1,0,0,"-"],traceroute:[1,0,0,"-"],udptunnel:[1,0,0,"-"],ccn:[0,0,0,"-"],tunnel:[1,0,0,"-"],nping:[1,0,0,"-"],rpmfuncs:[1,0,0,"-"],tun:[1,0,0,"-"],gretunnel:[1,0,0,"-"],"interface":[1,0,0,"-"],netns:[2,0,0,"-"],debfuncs:[1,0,0,"-"],ns3:[8,0,0,"-"],tcpdump:[1,0,0,"-"],udptest:[1,0,0,"-"],channel:[1,0,0,"-"]},"nepi.resources.ns3.classes.binary_error_model":{NS3BinaryErrorModel:[11,3,1,""]},"nepi.resources.planetlab.openvswitch":{ovs:[19,0,0,"-"],ovsport:[19,0,0,"-"]},"nepi.resources.omf":{node:[4,0,0,"-"],omf_client:[4,0,0,"-"],messages_6:[4,0,0,"-"],omf5_api:[4,0,0,"-"],omf_api_factory:[4,0,0,"-"],omf6_parser:[4,0,0,"-"],omf_resource:[4,0,0,"-"],application:[4,0,0,"-"],messages_5_4:[4,0,0,"-"],"interface":[4,0,0,"-"],omf6_api:[4,0,0,"-"],wilabt_node:[4,0,0,"-"],channel:[4,0,0,"-"]},"nepi.util.guid.GuidGenerator":{next:[16,1,1,""]},"nepi.resources.ns3.ns3simulation.NS3Simulation":{ns3_set:[6,1,1,""],invoke:[6,1,1,""],create:[6,1,1,""],stop:[6,1,1,""],factory:[6,1,1,""],start:[6,1,1,""],client:[6,4,1,""],shutdown:[6,1,1,""],flush:[6,1,1,""],ns3_get:[6,1,1,""]},"nepi.resources.ns3.classes.mesh_point_device":{NS3MeshPointDevice:[11,3,1,""]},"nepi.resources.linux.tcpdump":{LinuxTcpdump:[1,3,1,""]},"nepi.util.parallel":{WorkerThread:[16,3,1,""],ParallelRun:[16,3,1,""]},"nepi.util.plotter":{PFormats:[16,3,1,""],ECPlotter:[16,3,1,""]},"nepi.resources.planetlab.tap.PlanetlabTap":{node:[9,4,1,""],valid_connection:[9,1,1,""],vif_name_file:[9,4,1,""],gre_connect:[9,1,1,""],upload_start_command:[9,1,1,""],wait_vif_name:[9,1,1,""],upload_sources:[9,1,1,""]},"nepi.resources.linux.ccn.ccnpoke.LinuxCCNPoke":{do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.execution.ec.ECState":{TERMINATED:[10,4,1,""],RUNNING:[10,4,1,""],RELEASED:[10,4,1,""],FAILED:[10,4,1,""]},"nepi.resources.ns3.classes.tap_bridge":{NS3TapBridge:[11,3,1,""]},"nepi.resources.linux.gretunnel.LinuxGRETunnel":{valid_connection:[1,1,1,""],verify_connection:[1,1,1,""],initiate_connection:[1,1,1,""],establish_connection:[1,1,1,""],log_message:[1,1,1,""],terminate_connection:[1,1,1,""],get_endpoints:[1,1,1,""],check_state_connection:[1,1,1,""]},"nepi.data":{processing:[15,0,0,"-"]},"nepi.resources.planetlab.sfa_node.PlanetlabSfaNode":{sfaapi:[9,4,1,""],do_release:[9,1,1,""],valid_connection:[9,1,1,""],do_provision:[9,1,1,""],do_discover:[9,1,1,""],fail_sfaapi:[9,1,1,""],fail_not_enough_nodes:[9,1,1,""],fail_node_not_alive:[9,1,1,""],fail_discovery:[9,1,1,""],fail_node_not_available:[9,1,1,""]},"nepi.resources.planetlab.tun":{PlanetlabTun:[9,3,1,""]},"nepi.resources.ns3.ns3server.NS3WrapperMessage":{SET:[6,4,1,""],INVOKE:[6,4,1,""],GET:[6,4,1,""],CREATE:[6,4,1,""],STOP:[6,4,1,""],FACTORY:[6,4,1,""],START:[6,4,1,""],SHUTDOWN:[6,4,1,""],FLUSH:[6,4,1,""]},"nepi.resources.ns3.ns3netdevice":{NS3BaseNetDevice:[6,3,1,""]},"nepi.resources.planetlab.vroute.PlanetlabVroute":{node:[9,4,1,""],tap:[9,4,1,""],valid_connection:[9,1,1,""],do_release:[9,1,1,""],do_deploy:[9,1,1,""],do_start:[9,1,1,""],upload_start_command:[9,1,1,""],do_stop:[9,1,1,""],upload_sources:[9,1,1,""]},"nepi.resources.ns3":{ns3wrapper_debug:[6,0,0,"-"],ns3errorratemodel:[6,0,0,"-"],ns3errormodel:[6,0,0,"-"],ns3wifiphy:[6,0,0,"-"],ns3wifimac:[6,0,0,"-"],ns3arpl3protocol:[6,0,0,"-"],ns3route:[6,0,0,"-"],ns3dceapplication:[6,0,0,"-"],resource_manager_generator:[6,0,0,"-"],ns3icmpv4l4protocol:[6,0,0,"-"],ns3propagationlossmodel:[6,0,0,"-"],ns3simulation:[6,0,0,"-"],ns3pipechanel:[6,0,0,"-"],ns3queue:[6,0,0,"-"],ns3wrapper:[6,0,0,"-"],ns3mobilitymodel:[6,0,0,"-"],ns3propagationdelaymodel:[6,0,0,"-"],ns3fdnetdevice:[6,0,0,"-"],ns3channel:[6,0,0,"-"],ns3ccndceapplication:[6,0,0,"-"],ns3wifiremotestationmanager:[6,0,0,"-"],ns3client:[6,0,0,"-"],ns3dcehelper:[6,0,0,"-"],ns3wifichannel:[6,0,0,"-"],ns3node:[6,0,0,"-"],ns3wifinetdevice:[6,0,0,"-"],ns3ipv4l3protocol:[6,0,0,"-"],ns3server:[6,0,0,"-"],ns3netdevice:[6,0,0,"-"],ns3base:[6,0,0,"-"],classes:[11,0,0,"-"],ns3application:[6,0,0,"-"]},"nepi.resources.ns3.ns3wifiphy.NS3BaseWifiPhy":{device:[6,4,1,""],node:[6,4,1,""],channel:[6,4,1,""]},"nepi.resources.linux.nping.LinuxNPing":{do_deploy:[1,1,1,""],valid_connection:[1,1,1,""]},"nepi.execution.scheduler.TaskStatus":{NEW:[10,4,1,""],DONE:[10,4,1,""],ERROR:[10,4,1,""]},"nepi.resources.linux.ns3.ns3pingdceapplication":{LinuxDcePing:[8,3,1,""]},"nepi.util.serializer.SFormats":{XML:[16,4,1,""]},"nepi.resources.ns3.ns3simulation":{NS3Simulation:[6,3,1,""]},"nepi.resources.ns3.classes.nist_error_rate_model":{NS3NistErrorRateModel:[11,3,1,""]},"nepi.resources.netns":{netnswrapper:[20,0,0,"-"],netnsbase:[20,0,0,"-"],netnsserver:[20,0,0,"-"],netnsipv4address:[20,0,0,"-"],netnswrapper_debug:[20,0,0,"-"],netnsapplication:[20,0,0,"-"],netnsnodeinterface:[20,0,0,"-"],netnsinterface:[20,0,0,"-"],netnsemulation:[20,0,0,"-"],netnsnode:[20,0,0,"-"],netnsroute:[20,0,0,"-"],netnsclient:[20,0,0,"-"],netnsswitch:[20,0,0,"-"]},"nepi.util.parsers.xml_parser.ECXMLParser":{from_xml:[23,1,1,""],to_xml:[23,1,1,""]},"nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model":{NS3Kun2600MhzPropagationLossModel:[11,3,1,""]},"nepi.resources.netns.netnsswitch.NetNSSwitch":{"interface":[20,4,1,""],node:[20,4,1,""],emulation:[20,4,1,""]},"nepi.resources.ns3.classes.constant_speed_propagation_delay_model":{NS3ConstantSpeedPropagationDelayModel:[11,3,1,""]},"nepi.resources.ns3.ns3errormodel":{NS3BaseErrorModel:[6,3,1,""]},"nepi.resources.linux.node.OSType":{FEDORA_12:[1,4,1,""],FEDORA_14:[1,4,1,""],FEDORA:[1,4,1,""],FEDORA_8:[1,4,1,""],UBUNTU:[1,4,1,""],DEBIAN:[1,4,1,""]},"nepi.data.processing.ccn.parser":{annotate_cn_graph:[3,2,1,""],process_content_history_logs:[3,2,1,""],process_content_history:[3,2,1,""],ccn_consumers:[3,2,1,""],is_control:[3,2,1,""],ccn_producers:[3,2,1,""],annotate_cn_node:[3,2,1,""],parse_file:[3,2,1,""],load_content_history:[3,2,1,""],dump_content_history:[3,2,1,""]},"nepi.resources.planetlab.ns3":{fdudptunnel:[7,0,0,"-"],tuntapfdlink:[7,0,0,"-"]},"nepi.resources.ns3.ns3netdevice.NS3BaseNetDevice":{node:[6,4,1,""],queue:[6,4,1,""],ascii_helper_uuid:[6,4,1,""],channel:[6,4,1,""],device_helper_uuid:[6,4,1,""]},"nepi.resources.ns3.ns3wrapper.NS3Wrapper":{is_started:[6,4,1,""],debuger:[6,4,1,""],start:[6,1,1,""],invoke:[6,1,1,""],get:[6,1,1,""],replace_kwargs:[6,1,1,""],create:[6,1,1,""],stop:[6,1,1,""],factory:[6,1,1,""],is_running:[6,4,1,""],ns3:[6,4,1,""],get_object:[6,1,1,""],set:[6,1,1,""],make_uuid:[6,1,1,""],shutdown:[6,1,1,""],replace_args:[6,1,1,""],logger:[6,4,1,""],allowed_types:[6,4,1,""],is_finished:[6,4,1,""]},"nepi.resources.planetlab.node.PlanetlabNode":{plapi:[9,4,1,""],do_release:[9,1,1,""],valid_connection:[9,1,1,""],lock:[9,4,1,""],do_provision:[9,1,1,""],do_discover:[9,1,1,""],fail_plapi:[9,1,1,""],fail_not_enough_nodes:[9,1,1,""],fail_node_not_alive:[9,1,1,""],fail_discovery:[9,1,1,""],fail_node_not_available:[9,1,1,""]},"nepi.resources.linux.ns3.tuntapfdlink.LinuxTunTapFdLink":{node:[8,4,1,""],tap:[8,4,1,""],fdnetdevice:[8,4,1,""],fdnode:[8,4,1,""],upload_start_command:[8,1,1,""],do_deploy:[8,1,1,""],do_start:[8,1,1,""],tapnode:[8,4,1,""],upload_sources:[8,1,1,""]},"nepi.resources.ns3.classes.friis_propagation_loss_model":{NS3FriisPropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.ns3base.NS3Base":{node:[6,4,1,""],set:[6,1,1,""],uuid:[6,4,1,""],trace:[6,1,1,""],get:[6,1,1,""],do_provision:[6,1,1,""],state:[6,4,1,""],simulation:[6,4,1,""],do_deploy:[6,1,1,""],connected:[6,4,1,""],do_start:[6,1,1,""],do_stop:[6,1,1,""]},"nepi.resources.linux.udptunnel":{LinuxUdpTunnel:[1,3,1,""]},"nepi.resources.ns3.classes.jakes_propagation_loss_model":{NS3JakesPropagationLossModel:[11,3,1,""]},"nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication":{LinuxNS3DceFIBEntry:[14,3,1,""]},"nepi.resources.ns3.classes.sta_wifi_mac":{NS3StaWifiMac:[11,3,1,""]},"nepi.resources.linux.ns3":{tuntapfdlink:[8,0,0,"-"],fdudptunnel:[8,0,0,"-"],ns3simulation:[8,0,0,"-"],ccn:[14,0,0,"-"],ns3client:[8,0,0,"-"],ns3pingdceapplication:[8,0,0,"-"],ns3dceapplication:[8,0,0,"-"]},"nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication":{LinuxNS3DceCCNPoke:[14,3,1,""]},"nepi.resources.ns3.classes.single_model_spectrum_channel":{NS3SingleModelSpectrumChannel:[11,3,1,""]},"nepi.resources.ns3.classes.lte_ue_net_device":{NS3LteUeNetDevice:[11,3,1,""]},"nepi.resources.ns3.ns3server":{get_options:[6,2,1,""],run_server:[6,2,1,""],close_socket:[6,2,1,""],recv_msg:[6,2,1,""],open_socket:[6,2,1,""],handle_message:[6,2,1,""],send_reply:[6,2,1,""],NS3WrapperMessage:[6,3,1,""]},"nepi.execution.trace.Trace":{help:[10,4,1,""],name:[10,4,1,""]},"nepi.resources.ns3.ns3ipv4l3protocol.NS3BaseIpv4L3Protocol":{node:[6,4,1,""]},"nepi.resources.linux.node":{OSType:[1,3,1,""],LinuxNode:[1,3,1,""],ExitCode:[1,3,1,""]},"nepi.resources.omf.wilabt_node.WilabtSfaNode":{execute:[4,1,1,""],do_release:[4,1,1,""],valid_connection:[4,1,1,""],do_provision:[4,1,1,""],do_discover:[4,1,1,""],sfaapi:[4,4,1,""],fail_sfaapi:[4,1,1,""],do_deploy:[4,1,1,""],fail_not_enough_nodes:[4,1,1,""],fail_node_not_alive:[4,1,1,""],fail_discovery:[4,1,1,""],fail_node_not_available:[4,1,1,""]},"nepi.resources.linux.ns3.tuntapfdlink":{LinuxTunTapFdLink:[8,3,1,""]},"nepi.resources.ns3.ns3client.NS3Client":{set:[6,1,1,""],invoke:[6,1,1,""],get:[6,1,1,""],create:[6,1,1,""],stop:[6,1,1,""],factory:[6,1,1,""],start:[6,1,1,""],shutdown:[6,1,1,""],flush:[6,1,1,""]},"nepi.resources.omf.omf6_api":{OMF6API:[4,3,1,""]},"nepi.resources.ns3.classes.constant_rate_wifi_manager":{NS3ConstantRateWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.simple_channel":{NS3SimpleChannel:[11,3,1,""]},"nepi.resources.ns3.classes.emu_net_device":{NS3EmuNetDevice:[11,3,1,""]},"nepi.resources.netns.netnsroute":{NetNSIPv4Route:[20,3,1,""]},"nepi.resources.netns.netnsbase.NetNSBase":{set:[20,1,1,""],uuid:[20,4,1,""],trace:[20,1,1,""],get:[20,1,1,""],do_provision:[20,1,1,""],state:[20,4,1,""],do_deploy:[20,1,1,""],connected:[20,4,1,""],do_start:[20,1,1,""],do_stop:[20,1,1,""]},"nepi.resources.linux.ccn.ccnpingserver":{LinuxCCNPingServer:[0,3,1,""]},"nepi.resources.ns3.ns3dcehelper.NS3DceHelper":{dce_manager_uuid:[6,4,1,""],dce_application_uuid:[6,4,1,""],dce_manager_lock:[6,4,1,""],dce_application_lock:[6,4,1,""]},"nepi.resources.omf.messages_5_4":{MessageHandler:[4,3,1,""]},"nepi.resources.linux.node.LinuxNode":{usr_dir:[1,4,1,""],node_home:[1,4,1,""],do_release:[1,1,1,""],install_packages:[1,1,1,""],find_home:[1,1,1,""],kill:[1,1,1,""],valid_connection:[1,1,1,""],download:[1,1,1,""],wait_pid:[1,1,1,""],nepi_home:[1,4,1,""],clean_processes:[1,1,1,""],bin_dir:[1,4,1,""],format_environment:[1,1,1,""],upload_command:[1,1,1,""],mkdir:[1,1,1,""],home_dir:[1,4,1,""],filter_existing_files:[1,1,1,""],run_home:[1,4,1,""],getpid:[1,1,1,""],get_os:[1,1,1,""],src_dir:[1,4,1,""],exp_dir:[1,4,1,""],localhost:[1,4,1,""],rmdir:[1,1,1,""],status:[1,1,1,""],run:[1,1,1,""],clean_experiment:[1,1,1,""],share_dir:[1,4,1,""],do_provision:[1,1,1,""],use_rpm:[1,4,1,""],wait_run:[1,1,1,""],do_deploy:[1,1,1,""],exp_home:[1,4,1,""],log_message:[1,1,1,""],use_deb:[1,4,1,""],copy:[1,1,1,""],is_alive:[1,1,1,""],clean_home:[1,1,1,""],execute:[1,1,1,""],install_packages_command:[1,1,1,""],lib_dir:[1,4,1,""],upload:[1,1,1,""],check_errors:[1,1,1,""],check_output:[1,1,1,""],remove_packages:[1,1,1,""],exitcode:[1,1,1,""],os:[1,4,1,""],run_and_wait:[1,1,1,""]},"nepi.resources.ns3.classes.yans_wifi_channel":{NS3YansWifiChannel:[11,3,1,""]},"nepi.resources.ns3.classes.binary_error_sixlow_model":{NS3BinaryErrorSixlowModel:[11,3,1,""]},"nepi.resources.omf.omf_resource":{ResourceGateway:[4,3,1,""],OMFResource:[4,3,1,""]},"nepi.resources.netns.netnsbase":{NetNSBase:[20,3,1,""]},"nepi.resources.planetlab.vroute":{PlanetlabVroute:[9,3,1,""]},"nepi.resources.ns3.classes.csma_net_device":{NS3CsmaNetDevice:[11,3,1,""]},"nepi.resources.ns3.ns3wrapper_debug":{NS3WrapperDebuger:[6,3,1,""]},"nepi.resources.linux.ns3.fdudptunnel":{LinuxNs3FdUdpTunnel:[8,3,1,""]},"nepi.resources.ns3.classes.red_queue":{NS3RedQueue:[11,3,1,""]},"nepi.resources.linux.tap":{LinuxTap:[1,3,1,""]},"nepi.resources.ns3.classes.list_error_model":{NS3ListErrorModel:[11,3,1,""]},"nepi.resources.ns3.classes.udp_client":{NS3UdpClient:[11,3,1,""]},"nepi.resources.omf.node":{OMFNode:[4,3,1,""]},"nepi.resources.linux.ccn.ccnd.LinuxCCND":{valid_connection:[0,1,1,""],state:[0,4,1,""],do_deploy:[0,1,1,""],version:[0,4,1,""],do_start:[0,1,1,""],do_stop:[0,1,1,""],upload_start_command:[0,1,1,""],path:[0,4,1,""]},"nepi.resources.linux.interface":{LinuxInterface:[1,3,1,""]},"nepi.resources.ns3.classes.non_communicating_net_device":{NS3NonCommunicatingNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model":{NS3ItuR1411LosPropagationLossModel:[11,3,1,""]},"nepi.resources.linux.ccn.ccnping":{LinuxCCNPing:[0,3,1,""]},"nepi.resources.ns3.classes.lr_wpan_net_device":{NS3LrWpanNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.icmpv6l4protocol":{NS3Icmpv6L4Protocol:[11,3,1,""]},"nepi.resources.ns3.classes.tcp_l4protocol":{NS3TcpL4Protocol:[11,3,1,""]},"nepi.resources.linux.netns.netnsclient":{LinuxNetNSClient:[2,3,1,""]},"nepi.resources.ns3.ns3ipv4l3protocol":{NS3BaseIpv4L3Protocol:[6,3,1,""]},"nepi.resources.ns3.classes.onoe_wifi_manager":{NS3OnoeWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model":{NS3TwoRayGroundPropagationLossModel:[11,3,1,""]},"nepi.resources.linux.netns.netnsclient.LinuxNetNSClient":{set:[2,1,1,""],send_msg:[2,1,1,""],invoke:[2,1,1,""],get:[2,1,1,""],create:[2,1,1,""],emulation:[2,4,1,""],shutdown:[2,1,1,""],flush:[2,1,1,""]},"nepi.resources.linux.ns3.ns3simulation.LinuxNS3Simulation":{ns3_build_location:[8,4,1,""],socket_name:[8,4,1,""],do_release:[8,1,1,""],do_start:[8,1,1,""],ns3_src_location:[8,4,1,""],valid_connection:[8,1,1,""],replace_paths:[8,1,1,""],dce_src_location:[8,4,1,""],enable_dce:[8,4,1,""],state:[8,4,1,""],ns3_repo:[8,4,1,""],do_stop:[8,1,1,""],upload_sources:[8,1,1,""],pygccxml_version:[8,4,1,""],configure:[8,1,1,""],trace:[8,1,1,""],wait_remote_socket:[8,1,1,""],do_deploy:[8,1,1,""],remote_socket:[8,4,1,""],dce_helper:[8,4,1,""],dce_version:[8,4,1,""],dce_repo:[8,4,1,""],upload_extra_sources:[8,1,1,""],upload_start_command:[8,1,1,""]},"nepi.resources.ns3.classes.point_to_point_net_device":{NS3PointToPointNetDevice:[11,3,1,""]},"nepi.resources.planetlab.openvswitch.ovsport.PlanetlabOVSPort":{node:[19,4,1,""],ovsswitch:[19,4,1,""],establish_udp_connection:[19,1,1,""],valid_connection:[19,1,1,""],initiate_udp_connection:[19,1,1,""],do_release:[19,1,1,""],do_deploy:[19,1,1,""],port_number:[19,4,1,""],check_status:[19,1,1,""],do_provision:[19,1,1,""],terminate_connection:[19,1,1,""],create_port:[19,1,1,""],verify_connection:[19,1,1,""]},"nepi.resources.linux.udptest":{LinuxUdpTest:[1,3,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication":{LinuxNS3DceCCNCat:[14,3,1,""]},"nepi.resources.ns3.ns3wifinetdevice":{NS3BaseWifiNetDevice:[6,3,1,""]},"nepi.resources.ns3.ns3route":{NS3Route:[6,3,1,""]},"nepi.resources.ns3.classes.bulk_send_application":{NS3BulkSendApplication:[11,3,1,""]},"nepi.execution":{resource:[10,0,0,"-"],trace:[10,0,0,"-"],tags:[10,0,0,"-"],runner:[10,0,0,"-"],attribute:[10,0,0,"-"],ec:[10,0,0,"-"],scheduler:[10,0,0,"-"]},"nepi.resources.netns.netnsipv4address.NetNSIPv4Address":{"interface":[20,4,1,""],node:[20,4,1,""],emulation:[20,4,1,""]},"nepi.resources.planetlab.ns3.tuntapfdlink.PlanetlabTunTapFdLink":{upload_sources:[7,1,1,""],tap:[7,4,1,""],fdnetdevice:[7,4,1,""]},"nepi.resources.ns3.ns3node":{NS3BaseNode:[6,3,1,""]},"nepi.util.environ":{backticks:[16,2,1,""],execute:[16,2,1,""]},"nepi.util.guid":{GuidGenerator:[16,3,1,""]},"nepi.util.parsers":{xml_parser:[23,0,0,"-"]},"nepi.execution.attribute.Flags":{NoWrite:[10,4,1,""],Reserved:[10,4,1,""],NoRead:[10,4,1,""],Global:[10,4,1,""],Construct:[10,4,1,""],Filter:[10,4,1,""],Design:[10,4,1,""],Credential:[10,4,1,""]},"nepi.resources.omf.omf_api_factory":{OMFAPIFactory:[4,3,1,""]},"nepi.resources.ns3.ns3errormodel.NS3BaseErrorModel":{device:[6,4,1,""]},"nepi.resources.omf.application.OMFApplication":{node:[4,4,1,""],check_deploy:[4,1,1,""],valid_connection:[4,1,1,""],add_set_hook:[4,1,1,""],do_release:[4,1,1,""],do_deploy:[4,1,1,""],check_start:[4,1,1,""],stdin_hook:[4,1,1,""],do_start:[4,1,1,""],check_release:[4,1,1,""],trace:[4,1,1,""],do_stop:[4,1,1,""],exp_id:[4,4,1,""]},"nepi.resources.linux.ccn.ccncat":{LinuxCCNCat:[0,3,1,""]},"nepi.util.sfarspec_proc.SfaRSpecProcessing":{parse_sfa_rspec:[16,1,1,""],build_sfa_rspec:[16,1,1,""],make_dict_rec:[16,1,1,""]},"nepi.resources.netns.netnsnodeinterface":{NetNSNodeInterface:[20,3,1,""]},"nepi.resources.ns3.classes.udp_echo_client":{NS3UdpEchoClient:[11,3,1,""]},"nepi.resources.planetlab.openvswitch.ovs.PlanetlabOVSSwitch":{node:[19,4,1,""],do_provision:[19,1,1,""],check_sliver_ovs:[19,1,1,""],servers_on:[19,1,1,""],do_release:[19,1,1,""],create_bridge:[19,1,1,""],do_deploy:[19,1,1,""],valid_connection:[19,1,1,""],assign_controller:[19,1,1,""],ovs_status:[19,1,1,""]},"nepi.resources.linux.tunnel":{LinuxTunnel:[1,3,1,""]},"nepi.resources.ns3.classes.point_to_point_channel":{NS3PointToPointChannel:[11,3,1,""]},"nepi.resources.ns3.ns3wifimac.NS3BaseWifiMac":{node:[6,4,1,""],device:[6,4,1,""]},"nepi.resources.ns3.classes.fd_net_device":{NS3FdNetDevice:[11,3,1,""]},"nepi.execution.resource.ResourceState":{PROVISIONED:[10,4,1,""],RESERVED:[10,4,1,""],FAILED:[10,4,1,""],STARTED:[10,4,1,""],DISCOVERED:[10,4,1,""],RELEASED:[10,4,1,""],STOPPED:[10,4,1,""],READY:[10,4,1,""],NEW:[10,4,1,""]},"nepi.resources.omf.omf_resource.ResourceGateway":{TestbedtoGateway:[4,4,1,""],AMtoGateway:[4,4,1,""]},"nepi.resources.ns3.classes.simple_net_device":{NS3SimpleNetDevice:[11,3,1,""]},"nepi.resources.planetlab.tap":{PlanetlabTap:[9,3,1,""]},"nepi.resources.linux.application":{LinuxApplication:[1,3,1,""]},"nepi.util.manifoldapi.MANIFOLDAPI":{get_session_key:[16,1,1,""],get_resource_urn:[16,1,1,""],get_slice_resources:[16,1,1,""],get_resource_info:[16,1,1,""],add_resource_to_slice:[16,1,1,""],api:[16,4,1,""],remove_resource_from_slice:[16,1,1,""]},"nepi.data.processing":{ccn:[3,0,0,"-"],ping:[22,0,0,"-"]},"nepi.resources.ns3.classes.arp_l3protocol":{NS3ArpL3Protocol:[11,3,1,""]},"nepi.resources.ns3.ns3propagationdelaymodel.NS3BasePropagationDelayModel":{channel:[6,4,1,""],simulation:[6,4,1,""]},"nepi.resources.ns3.ns3ccndceapplication":{NS3BaseCCNDceApplication:[6,3,1,""]},"nepi.util.parallel.WorkerThread":{attach:[16,1,1,""],run:[16,1,1,""],QUIT:[16,3,1,""],quit:[16,1,1,""]},"nepi.resources.linux.ccn.ccncat.LinuxCCNCat":{do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.resources.ns3.classes.constant_position_mobility_model":{NS3ConstantPositionMobilityModel:[11,3,1,""]},"nepi.resources.omf.messages_6.MessageHandler":{create_function:[4,1,1,""],request_function:[4,1,1,""],configure_function:[4,1,1,""],release_function:[4,1,1,""]},"nepi.resources.ns3.classes.receive_list_error_model":{NS3ReceiveListErrorModel:[11,3,1,""]},"nepi.execution.ec.ExperimentController":{get_task:[10,1,1,""],load:[10,5,1,""],stop:[10,1,1,""],set:[10,1,1,""],nthreads:[10,4,1,""],run_id:[10,4,1,""],trace_enabled:[10,1,1,""],serialize:[10,1,1,""],discover:[10,1,1,""],failure_level:[10,4,1,""],inform_failure:[10,1,1,""],abort:[10,4,1,""],shutdown:[10,1,1,""],set_global:[10,1,1,""],get_provision_time:[10,1,1,""],register_connection:[10,1,1,""],get_failed_time:[10,1,1,""],get_ready_time:[10,1,1,""],schedule:[10,1,1,""],get_global:[10,1,1,""],start:[10,1,1,""],state:[10,1,1,""],get_discover_time:[10,1,1,""],deploy:[10,1,1,""],persist:[10,4,1,""],local_dir:[10,4,1,""],logger:[10,4,1,""],wait:[10,1,1,""],resources:[10,4,1,""],enable_trace:[10,1,1,""],ecstate:[10,4,1,""],trace:[10,1,1,""],get:[10,1,1,""],remove_resource:[10,1,1,""],get_stop_time:[10,1,1,""],get_release_time:[10,1,1,""],get_attribute:[10,1,1,""],wait_started:[10,1,1,""],register_condition:[10,1,1,""],get_traces:[10,1,1,""],exp_id:[10,4,1,""],set_with_conditions:[10,1,1,""],provision:[10,1,1,""],fm:[10,4,1,""],get_resource:[10,1,1,""],run_dir:[10,4,1,""],filter_resources:[10,1,1,""],wait_released:[10,1,1,""],save:[10,1,1,""],wait_deployed:[10,1,1,""],netgraph:[10,4,1,""],get_resources_by_type:[10,1,1,""],plot:[10,1,1,""],register_resource:[10,1,1,""],exp_dir:[10,4,1,""],get_start_time:[10,1,1,""],release:[10,1,1,""],wait_finished:[10,1,1,""],get_attributes:[10,1,1,""]},"nepi.resources.linux.ping":{LinuxPing:[1,3,1,""]},"nepi.resources.ns3.classes.random_walk2d_mobility_model":{NS3RandomWalk2dMobilityModel:[11,3,1,""]},"nepi.execution.scheduler":{Task:[10,3,1,""],HeapScheduler:[10,3,1,""],TaskStatus:[10,3,1,""]},"nepi.resources.omf.wilabt_node":{WilabtSfaNode:[4,3,1,""]},"nepi.resources.linux.traceroute":{LinuxTraceroute:[1,3,1,""]},"nepi.resources.ns3.ns3propagationlossmodel.NS3BasePropagationLossModel":{channel:[6,4,1,""],simulation:[6,4,1,""]},"nepi.resources.linux.ns3.ns3client.LinuxNS3Client":{set:[8,1,1,""],send_msg:[8,1,1,""],invoke:[8,1,1,""],get:[8,1,1,""],create:[8,1,1,""],stop:[8,1,1,""],factory:[8,1,1,""],simulation:[8,4,1,""],start:[8,1,1,""],shutdown:[8,1,1,""],flush:[8,1,1,""]},"nepi.util.manifoldapi":{MANIFOLDAPIFactory:[16,3,1,""],MANIFOLDAPI:[16,3,1,""]},"nepi.resources.linux.channel.LinuxChannel":{log_message:[1,1,1,""],valid_connection:[1,1,1,""]},"nepi.resources.linux.ccn":{ccnpoke:[0,0,0,"-"],ccnapplication:[0,0,0,"-"],fibentry:[0,0,0,"-"],ccnr:[0,0,0,"-"],ccnpingserver:[0,0,0,"-"],ccncontent:[0,0,0,"-"],ccnd:[0,0,0,"-"],ccnpeek:[0,0,0,"-"],ccncat:[0,0,0,"-"],ccnping:[0,0,0,"-"]},"nepi.resources.ns3.classes.random_propagation_loss_model":{NS3RandomPropagationLossModel:[11,3,1,""]},"nepi.resources.omf.interface.OMFWifiInterface":{node:[4,4,1,""],valid_connection:[4,1,1,""],check_deploy:[4,1,1,""],do_release:[4,1,1,""],configure_iface:[4,1,1,""],do_deploy:[4,1,1,""],configure_ip:[4,1,1,""],configure_on_omf5:[4,1,1,""],configure_on_omf6:[4,1,1,""],check_release:[4,1,1,""],exp_id:[4,4,1,""],channel:[4,4,1,""]},"nepi.resources.ns3.ns3fdnetdevice":{NS3BaseFdNetDevice:[6,3,1,""]},"nepi.resources.ns3.classes.mesh_wifi_interface_mac":{NS3MeshWifiInterfaceMac:[11,3,1,""]},"nepi.resources.ns3.classes.oh_buildings_propagation_loss_model":{NS3OhBuildingsPropagationLossModel:[11,3,1,""]},"nepi.resources.omf.node.OMFNode":{exp_id:[4,4,1,""],do_deploy:[4,1,1,""],do_release:[4,1,1,""],valid_connection:[4,1,1,""]},"nepi.resources.ns3.classes.adhoc_wifi_mac":{NS3AdhocWifiMac:[11,3,1,""]},"nepi.resources.netns.netnswrapper_debug":{NetNSWrapperDebuger:[20,3,1,""]},"nepi.util.netgraph":{NetGraph:[16,3,1,""],TopologyType:[16,3,1,""]},"nepi.execution.ec":{ECState:[10,3,1,""],FailureLevel:[10,3,1,""],FailureManager:[10,3,1,""],ExperimentController:[10,3,1,""]},"nepi.resources.ns3.ns3channel.NS3BaseChannel":{devices:[6,4,1,""],simulation:[6,4,1,""]},"nepi.resources.ns3.classes.aarfcd_wifi_manager":{NS3AarfcdWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.icmpv4l4protocol":{NS3Icmpv4L4Protocol:[11,3,1,""]},"nepi.resources.omf.omf6_parser.OMF6Parser":{check_mailbox:[4,1,1,""],handle:[4,1,1,""],init_mailbox:[4,1,1,""]},"nepi.resources.linux.ns3.ns3dceapplication":{LinuxNS3DceApplication:[8,3,1,""]},"nepi.resources.ns3.ns3wifimac":{NS3BaseWifiMac:[6,3,1,""]},"nepi.resources.linux.ccn.ccnr":{LinuxCCNR:[0,3,1,""]},"nepi.resources.netns.netnsnode.NetNSNode":{emulation:[20,4,1,""]},"nepi.resources.linux.ccn.ccnd":{LinuxCCND:[0,3,1,""]},"nepi.resources.linux.interface.LinuxInterface":{add_set_hooks:[1,1,1,""],node:[1,4,1,""],do_release:[1,1,1,""],valid_connection:[1,1,1,""],do_provision:[1,1,1,""],do_discover:[1,1,1,""],do_deploy:[1,1,1,""],set_hook_mtu:[1,1,1,""],log_message:[1,1,1,""],set_hook_up:[1,1,1,""],channel:[1,4,1,""],load_configuration:[1,1,1,""]},"nepi.resources.netns.netnsclient":{NetNSClient:[20,3,1,""]},"nepi.resources.ns3.classes.rraa_wifi_manager":{NS3RraaWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.burst_error_model":{NS3BurstErrorModel:[11,3,1,""]},"nepi.resources.planetlab.node":{PlanetlabNode:[9,3,1,""]},"nepi.resources.ns3.classes.amrr_wifi_manager":{NS3AmrrWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.rate_error_model":{NS3RateErrorModel:[11,3,1,""]},"nepi.resources.ns3.ns3application":{NS3BaseApplication:[6,3,1,""]},"nepi.util.serializer.ECSerializer":{load:[16,1,1,""],save:[16,1,1,""],serialize:[16,1,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccnddceapplication.LinuxNS3DceCCND":{version:[14,4,1,""]},"nepi.resources.linux.ccn.ccncontent.LinuxCCNContent":{node:[0,4,1,""],valid_connection:[0,1,1,""],ccnr:[0,4,1,""],ccnd:[0,4,1,""],do_deploy:[0,1,1,""],do_start:[0,1,1,""],upload_start_command:[0,1,1,""]},"nepi.resources.ns3.classes.cara_wifi_manager":{NS3CaraWifiManager:[11,3,1,""]},"nepi.resources.ns3.classes.constant_acceleration_mobility_model":{NS3ConstantAccelerationMobilityModel:[11,3,1,""]},"nepi.resources.ns3.classes.yans_error_rate_model":{NS3YansErrorRateModel:[11,3,1,""]},"nepi.resources.linux.ccn.ccnr.LinuxCCNR":{node:[0,4,1,""],valid_connection:[0,1,1,""],ccnd:[0,4,1,""],do_deploy:[0,1,1,""],do_start:[0,1,1,""],upload_start_command:[0,1,1,""]},"nepi.resources.linux.tunnel.LinuxTunnel":{app_home:[1,1,1,""],do_provision:[1,1,1,""],valid_connection:[1,1,1,""],verify_connection:[1,1,1,""],do_stop:[1,1,1,""],initiate_connection:[1,1,1,""],establish_connection:[1,1,1,""],do_deploy:[1,1,1,""],state:[1,4,1,""],run_home:[1,1,1,""],endpoint_mkdir:[1,1,1,""],do_start:[1,1,1,""],log_message:[1,1,1,""],endpoint1:[1,4,1,""],endpoint2:[1,4,1,""],terminate_connection:[1,1,1,""],get_endpoints:[1,1,1,""],check_state_connection:[1,1,1,""]},"nepi.resources.planetlab.plcapi":{PLCAPI:[9,3,1,""],PLCAPIFactory:[9,3,1,""]},"nepi.resources.netns.netnsinterface":{NetNSInterface:[20,3,1,""]},"nepi.util.plotter.ECPlotter":{plot:[16,1,1,""]},"nepi.resources.planetlab.plcapi.PLCAPIFactory":{create_api:[9,5,1,""],get_api:[9,5,1,""]},"nepi.resources.ns3.classes.random_propagation_delay_model":{NS3RandomPropagationDelayModel:[11,3,1,""]},"nepi.resources.ns3.classes.error_net_device":{NS3ErrorNetDevice:[11,3,1,""]},"nepi.util.netgraph.NetGraph":{topo_type:[16,4,1,""],add_node:[16,1,1,""],del_node_annotation:[16,1,1,""],targets:[16,1,1,""],node_annotation:[16,1,1,""],generate_topology:[16,1,1,""],annotate_edge:[16,1,1,""],set_target:[16,1,1,""],node_ip_annotations:[16,1,1,""],is_source:[16,1,1,""],select_target_zero:[16,1,1,""],nodes:[16,1,1,""],is_target:[16,1,1,""],set_source:[16,1,1,""],get_p2p_info:[16,1,1,""],select_random_source:[16,1,1,""],edge_net_annotation:[16,1,1,""],edges:[16,1,1,""],add_edge:[16,1,1,""],assign_p2p_ips:[16,1,1,""],topology:[16,4,1,""],annotate_node:[16,1,1,""],annotate_edge_net:[16,1,1,""],sources:[16,1,1,""],node_annotations:[16,1,1,""],del_edge_annotation:[16,1,1,""],order:[16,4,1,""],edge_annotation:[16,1,1,""],edge_annotations:[16,1,1,""],annotate_node_ip:[16,1,1,""]},"nepi.resources.netns.netnsemulation":{NetNSEmulation:[20,3,1,""]},"nepi.resources.ns3.ns3pipechanel.NS3BasePipeChannel":{node:[6,4,1,""],devices:[6,4,1,""]},"nepi.resources.ns3.classes.random_waypoint_mobility_model":{NS3RandomWaypointMobilityModel:[11,3,1,""]},"nepi.resources.omf.omf_client.OMFClient":{check_mailbox:[4,1,1,""],get:[4,1,1,""],unregister:[4,1,1,""],create:[4,1,1,""],register:[4,1,1,""],publish:[4,1,1,""],subscriptions:[4,1,1,""],purge:[4,1,1,""],subscribe:[4,1,1,""],retract:[4,1,1,""],unsubscribe:[4,1,1,""],ready:[4,4,1,""],nodes:[4,1,1,""],handle_omf_message:[4,1,1,""],start:[4,1,1,""],"delete":[4,1,1,""]},"nepi.util.netgraph.TopologyType":{STAR:[16,4,1,""],LINEAR:[16,4,1,""],LADDER:[16,4,1,""],TREE:[16,4,1,""],ADHOC:[16,4,1,""],MESH:[16,4,1,""]},"nepi.resources.ns3.classes.range_propagation_loss_model":{NS3RangePropagationLossModel:[11,3,1,""]},"nepi.resources.planetlab.sfa_node":{PlanetlabSfaNode:[9,3,1,""]},"nepi.resources.ns3.ns3arpl3protocol":{NS3BaseArpL3Protocol:[6,3,1,""]},"nepi.execution.scheduler.HeapScheduler":{next:[10,1,1,""],pending:[10,4,1,""],remove:[10,1,1,""],schedule:[10,1,1,""]},"nepi.resources.linux.ccn.ccnapplication.LinuxCCNApplication":{node:[0,4,1,""],ccnd:[0,4,1,""],do_deploy:[0,1,1,""],valid_connection:[0,1,1,""]},"nepi.resources.ns3.ns3wifichannel":{NS3BaseWifiChannel:[6,3,1,""]},"nepi.resources.linux.nping":{LinuxNPing:[1,3,1,""]},"nepi.resources.linux.ccn.fibentry":{LinuxFIBEntry:[0,3,1,""]},"nepi.execution.attribute.Attribute":{has_changed:[10,4,1,""],has_flag:[10,1,1,""],name:[10,4,1,""],"default":[10,4,1,""],get_value:[10,1,1,""],value:[10,4,1,""],is_valid_value:[10,1,1,""],range:[10,4,1,""],flags:[10,4,1,""],allowed:[10,4,1,""],set_value:[10,1,1,""],type:[10,4,1,""],help:[10,4,1,""]},"nepi.resources.linux.udptest.LinuxUdpTest":{upload_start_command:[1,1,1,""],do_deploy:[1,1,1,""],valid_connection:[1,1,1,""],do_start:[1,1,1,""]},"nepi.resources.linux.ccn.ccnapplication":{LinuxCCNApplication:[0,3,1,""]},"nepi.resources.ns3.classes.point_to_point_remote_channel":{NS3PointToPointRemoteChannel:[11,3,1,""]},"nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication":{LinuxNS3DceCCNPeek:[14,3,1,""]},"nepi.resources.planetlab.ns3.tuntapfdlink":{PlanetlabTunTapFdLink:[7,3,1,""]},"nepi.resources.ns3.resource_manager_generator":{create_ns3_rms:[6,2,1,""],template_traces:[6,2,1,""],select_base_class:[6,2,1,""],template_attributes:[6,2,1,""]},"nepi.util.sfaapi.SFAAPI":{blacklist_resource:[16,1,1,""],reserved:[16,1,1,""],blacklisted:[16,1,1,""],get_resources_hrn:[16,1,1,""],reserve_resource:[16,1,1,""],remove_all_from_slice:[16,1,1,""],get_slice_resources:[16,1,1,""],remove_resource_from_slice:[16,1,1,""],add_resource_to_slice:[16,1,1,""],add_resource_to_slice_batch:[16,1,1,""],release:[16,1,1,""],get_resources_info:[16,1,1,""]},"nepi.resources.ns3.classes.udp_l4protocol":{NS3UdpL4Protocol:[11,3,1,""]},"nepi.resources.netns.netnsemulation.NetNSEmulation":{emu_set:[20,1,1,""],invoke:[20,1,1,""],create:[20,1,1,""],client:[20,4,1,""],shutdown:[20,1,1,""],flush:[20,1,1,""],emu_get:[20,1,1,""]},"nepi.resources.ns3.classes.aloha_noack_net_device":{NS3AlohaNoackNetDevice:[11,3,1,""]},"nepi.resources.linux.mtr":{LinuxMtr:[1,3,1,""]},"nepi.resources.ns3.classes.ping6":{NS3Ping6:[11,3,1,""]},"nepi.execution.ec.FailureLevel":{RM_FAILURE:[10,4,1,""],OK:[10,4,1,""],EC_FAILURE:[10,4,1,""]},"nepi.resources.linux.tun":{LinuxTun:[1,3,1,""]},"nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model":{NS3HybridBuildingsPropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.classes.drop_tail_queue":{NS3DropTailQueue:[11,3,1,""]},"nepi.resources.ns3.ns3propagationlossmodel":{NS3BasePropagationLossModel:[6,3,1,""]},"nepi.resources.ns3.classes.nakagami_propagation_loss_model":{NS3NakagamiPropagationLossModel:[11,3,1,""]},"nepi.execution.resource":{ResourceManager:[10,3,1,""],populate_factory:[10,2,1,""],ResourceAction:[10,3,1,""],find_types:[10,2,1,""],ResourceState:[10,3,1,""],clsinit:[10,2,1,""],ResourceFactory:[10,3,1,""],clsinit_copy:[10,2,1,""],failtrap:[10,2,1,""]},"nepi.execution.attribute":{Attribute:[10,3,1,""],Flags:[10,3,1,""],Types:[10,3,1,""]},"nepi.resources.all.collector.Collector":{do_provision:[13,1,1,""],store_path:[13,4,1,""],do_deploy:[13,1,1,""],do_release:[13,1,1,""],valid_connection:[13,1,1,""]},"nepi.resources.ns3.classes.loopback_net_device":{NS3LoopbackNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model":{NS3ItuR1411NlosOverRooftopPropagationLossModel:[11,3,1,""]},"nepi.resources.ns3.ns3pipechanel":{NS3BasePipeChannel:[6,3,1,""]},"nepi.resources.ns3.classes.v4ping":{NS3V4Ping:[11,3,1,""]},"nepi.resources.ns3.classes.lte_simple_net_device":{NS3LteSimpleNetDevice:[11,3,1,""]},"nepi.resources.ns3.classes.dsrdsr_routing":{NS3dsrDsrRouting:[11,3,1,""]},"nepi.resources.ns3.classes.udp_echo_server":{NS3UdpEchoServer:[11,3,1,""]},"nepi.resources.ns3.classes.six_low_pan_net_device":{NS3SixLowPanNetDevice:[11,3,1,""]},"nepi.resources.linux.tap.LinuxTap":{vif_type:[1,4,1,""],IFF_TAP:[1,4,1,""],udp_connect:[1,1,1,""],do_release:[1,1,1,""],wait_file:[1,1,1,""],vif_type_flag:[1,4,1,""],do_start:[1,1,1,""],check_status:[1,1,1,""],establish_udp_connection:[1,1,1,""],valid_connection:[1,1,1,""],initiate_udp_connection:[1,1,1,""],state:[1,4,1,""],do_stop:[1,1,1,""],upload_sources:[1,1,1,""],node:[1,4,1,""],verify_connection:[1,1,1,""],gre_enabled:[1,4,1,""],vif_prefix:[1,4,1,""],gre_connect:[1,1,1,""],do_deploy:[1,1,1,""],sock_name:[1,4,1,""],IFF_TUN:[1,4,1,""],upload_start_command:[1,1,1,""],terminate_connection:[1,1,1,""]},"nepi.resources.linux.ns3.ccn":{ns3ccncatdceapplication:[14,0,0,"-"],ns3fibentrydceapplication:[14,0,0,"-"],ns3ccnpeekdceapplication:[14,0,0,"-"],ns3ccnrdceapplication:[14,0,0,"-"],ns3ccnddceapplication:[14,0,0,"-"],ns3ccndceapplication:[14,0,0,"-"],ns3ccnpokedceapplication:[14,0,0,"-"]},"nepi.resources.ns3.classes.node":{NS3Node:[11,3,1,""]},"nepi.resources.all.collector":{Collector:[13,3,1,""]},"nepi.data.processing.ping":{parser:[22,0,0,"-"]},"nepi.util.logger.Logger":{info:[16,1,1,""],log:[16,1,1,""],warning:[16,1,1,""],error:[16,1,1,""],debug:[16,1,1,""],log_message:[16,1,1,""],logger:[16,4,1,""]},"nepi.resources.linux.ping.LinuxPing":{upload_start_command:[1,1,1,""],do_deploy:[1,1,1,""],valid_connection:[1,1,1,""],do_start:[1,1,1,""]},"nepi.resources.omf.application":{OMFApplication:[4,3,1,""]},"nepi.resources.ns3.ns3queue":{NS3BaseQueue:[6,3,1,""]}},titleterms:{netn:[20,2],all:13,execut:10,ns3wrapper_debug:6,vrout:9,sta_wifi_mac:11,netnswrapper_debug:20,rpmfunc:1,waypoint_mobility_model:11,netnsnod:20,ns3wifiremotestationmanag:6,ccnpeek:0,ocb_wifi_mac:11,omf_api_factori:4,hybrid_buildings_propagation_loss_model:11,netnsswitch:20,packet_sink:11,icmpv6l4protocol:11,itu_r1411los_propagation_loss_model:11,udp_trace_cli:11,ns3propagationlossmodel:6,ns3ccnrdceapplic:14,platform:5,nist_error_rate_model:11,binary_error_sixlow_model:11,ccnpingserv:0,yans_wifi_channel:11,logger:16,point_to_point_channel:11,ns3ccnpeekdceappl:14,ccnping:0,random_direction2d_mobility_model:11,applic:[1,4],omf_client:4,lr_wpan_net_devic:11,ns3fibentrydceappl:14,timefunc:16,rout:1,sshfunc:16,resource_manager_gener:6,ccncontent:0,udptunnel:1,util:[16,23],tap_bridg:11,ns3ccncatdceappl:14,aarfcd_wifi_manag:11,ideal_wifi_manag:11,list_error_model:11,manifoldapi:16,ns3wrapper:6,omf5_api:4,jakes_propagation_loss_model:11,ns3fdnetdevic:6,on_off_appl:11,ns3wifimac:6,red_queu:11,ns3base:6,adhoc_wifi_mac:11,channel:[1,4],ns3ccnddceapplic:14,netnsclient:[20,2],ns3wifinetdevic:6,receive_list_error_model:11,fdudptunnel:[7,8],onoe_wifi_manag:11,ns3netdevic:6,itu_r1411nlos_over_rooftop_propagation_loss_model:11,range_propagation_loss_model:11,point_to_point_remote_channel:11,point_to_point_net_devic:11,csma_net_devic:11,ns3wifiphi:6,arf_wifi_manag:11,fd_net_devic:11,error_channel:11,collector:13,nepi:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],udp_l4protocol:11,ns3pingdceappl:8,ns3node:6,messages_6:4,rate_error_model:11,omf6_api:4,ns3icmpv4l4protocol:6,debfunc:1,content:[0,1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23],ns3pipechanel:6,fibentri:0,ns3applic:6,amrr_wifi_manag:11,attribut:10,core:5,ns3propagationdelaymodel:6,cara_wifi_manag:11,omf:4,udp_echo_serv:11,random_propagation_delay_model:11,ping6:11,ovsport:19,omf6_pars:4,constant_position_mobility_model:11,tun:[1,9],ns3client:[8,6],wilabt_nod:4,miscellan:5,okumura_hata_propagation_loss_model:11,ns3rout:6,ns3ccndceapplic:[14,6],messages_5_4:4,netnsipv4address:20,ccnpoke:0,lte_enb_net_devic:11,lte_ue_net_devic:11,netnsrout:20,yans_error_rate_model:11,tunnel:1,six_low_pan_net_devic:11,mesh_wifi_interface_mac:11,rraa_wifi_manag:11,schedul:10,modul:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23],bridge_net_devic:11,submodul:[0,6,7,8,1,19,9,2,10,16,23,13,11,3,14,4,22,20],wifi_net_devic:11,statfunc:16,drop_tail_queu:11,linux:[8,0,14,1,2],v4ping:11,tap:[1,9],constant_rate_wifi_manag:11,guid:16,binary_error_model:11,hierarchical_mobility_model:11,ns3queue:6,omf_resourc:4,parallel:16,constant_acceleration_mobility_model:11,gauss_markov_mobility_model:11,ipv4l3protocol:11,process:[3,15,22],netnsappl:20,interfac:[1,4],multi_model_spectrum_channel:11,aarf_wifi_manag:11,ap_wifi_mac:11,ns3dcehelp:6,tcpdump:1,radvd:11,csma_channel:11,icmpv4l4protocol:11,constant_speed_propagation_delay_model:11,minstrel_wifi_manag:11,oh_buildings_propagation_loss_model:11,subscriber_station_net_devic:11,xml_parser:23,nping:1,simple_channel:11,gretunnel:1,ccncat:0,ns3:[7,8,14,11,6],yans_wifi_phi:11,three_log_distance_propagation_loss_model:11,friis_propagation_loss_model:11,base_station_net_devic:11,tuntapfdlink:[7,8],plcapi:9,netnsinterfac:20,netnsemul:[20,2],ns3ipv4l3protocol:6,random_walk2d_mobility_model:11,netnsnodeinterfac:20,bulk_send_appl:11,mtr:1,udp_echo_cli:11,single_model_spectrum_channel:11,plotter:16,ns3ccnpokedceappl:14,arp_l3protocol:11,ccnapplic:0,virtual_net_devic:11,fixed_rss_loss_model:11,ns3errorratemodel:6,netgraph:16,ns3errormodel:6,kun2600mhz_propagation_loss_model:11,runner:10,parser:[3,22,23],indic:5,packag:[0,1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23],netnsbas:20,tag:10,tabl:5,ns3arpl3protocol:6,netnsserv:20,serial:16,log_distance_propagation_loss_model:11,tracerout:1,udp_client:11,sfaapi:16,sfa_nod:9,ccnr:0,dsrdsr_rout:11,ns3simul:[8,6],ping:[1,22],error_net_devic:11,random_waypoint_mobility_model:11,ccnd:0,udp_serv:11,nakagami_propagation_loss_model:11,burst_error_model:11,document:[],ns3mobilitymodel:6,error_channel_sixlow:11,node:[11,1,4,9],constant_velocity_mobility_model:11,sfarspec_proc:16,resourc:[0,6,7,8,1,19,9,2,10,13,21,11,14,4,20],trace:10,planetlab:[7,19,9],ns3channel:6,openvswitch:19,tcp_l4protocol:11,cost231propagation_loss_model:11,"class":11,aloha_noack_net_devic:11,mesh_point_devic:11,two_ray_ground_propagation_loss_model:11,rmatcher:16,ns3dceapplic:[8,6],data:[3,15,18,22],netnswrapp:20,matrix_propagation_loss_model:11,steady_state_random_waypoint_mobility_model:11,subpackag:[18,6,8,12,1,9,15,16,21],ns3wifichannel:6,non_communicating_net_devic:11,random_propagation_loss_model:11,ns3server:6,emu_net_devic:11,bridge_channel:11,lte_simple_net_devic:11,loopback_net_devic:11,ccn:[0,14,3],environ:16,execfunc:16,uan_channel:11,udptest:1,simple_net_devic:11}}) \ No newline at end of file diff --git a/doc/sphinx/_layout/modules.rst b/doc/sphinx/_layout/modules.rst new file mode 100644 index 00000000..6486b2cf --- /dev/null +++ b/doc/sphinx/_layout/modules.rst @@ -0,0 +1,7 @@ +nepi +==== + +.. toctree:: + :maxdepth: 4 + + nepi diff --git a/doc/sphinx/_layout/nepi.data.processing.ccn.rst b/doc/sphinx/_layout/nepi.data.processing.ccn.rst new file mode 100644 index 00000000..4b3bb6b2 --- /dev/null +++ b/doc/sphinx/_layout/nepi.data.processing.ccn.rst @@ -0,0 +1,22 @@ +nepi.data.processing.ccn package +================================ + +Submodules +---------- + +nepi.data.processing.ccn.parser module +-------------------------------------- + +.. automodule:: nepi.data.processing.ccn.parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.data.processing.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.data.processing.ping.rst b/doc/sphinx/_layout/nepi.data.processing.ping.rst new file mode 100644 index 00000000..56d3574d --- /dev/null +++ b/doc/sphinx/_layout/nepi.data.processing.ping.rst @@ -0,0 +1,22 @@ +nepi.data.processing.ping package +================================= + +Submodules +---------- + +nepi.data.processing.ping.parser module +--------------------------------------- + +.. automodule:: nepi.data.processing.ping.parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.data.processing.ping + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.data.processing.rst b/doc/sphinx/_layout/nepi.data.processing.rst new file mode 100644 index 00000000..6f22a0fa --- /dev/null +++ b/doc/sphinx/_layout/nepi.data.processing.rst @@ -0,0 +1,18 @@ +nepi.data.processing package +============================ + +Subpackages +----------- + +.. toctree:: + + nepi.data.processing.ccn + nepi.data.processing.ping + +Module contents +--------------- + +.. automodule:: nepi.data.processing + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.data.rst b/doc/sphinx/_layout/nepi.data.rst new file mode 100644 index 00000000..2841cdc0 --- /dev/null +++ b/doc/sphinx/_layout/nepi.data.rst @@ -0,0 +1,17 @@ +nepi.data package +================= + +Subpackages +----------- + +.. toctree:: + + nepi.data.processing + +Module contents +--------------- + +.. automodule:: nepi.data + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.execution.rst b/doc/sphinx/_layout/nepi.execution.rst new file mode 100644 index 00000000..c8f46ae0 --- /dev/null +++ b/doc/sphinx/_layout/nepi.execution.rst @@ -0,0 +1,70 @@ +nepi.execution package +====================== + +Submodules +---------- + +nepi.execution.attribute module +------------------------------- + +.. automodule:: nepi.execution.attribute + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.ec module +------------------------ + +.. automodule:: nepi.execution.ec + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.resource module +------------------------------ + +.. automodule:: nepi.execution.resource + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.runner module +---------------------------- + +.. automodule:: nepi.execution.runner + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.scheduler module +------------------------------- + +.. automodule:: nepi.execution.scheduler + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.tags module +-------------------------- + +.. automodule:: nepi.execution.tags + :members: + :undoc-members: + :show-inheritance: + +nepi.execution.trace module +--------------------------- + +.. automodule:: nepi.execution.trace + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.execution + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.all.rst b/doc/sphinx/_layout/nepi.resources.all.rst new file mode 100644 index 00000000..59459003 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.all.rst @@ -0,0 +1,22 @@ +nepi.resources.all package +========================== + +Submodules +---------- + +nepi.resources.all.collector module +----------------------------------- + +.. automodule:: nepi.resources.all.collector + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.all + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.ccn.rst b/doc/sphinx/_layout/nepi.resources.linux.ccn.rst new file mode 100644 index 00000000..871cb33f --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.ccn.rst @@ -0,0 +1,94 @@ +nepi.resources.linux.ccn package +================================ + +Submodules +---------- + +nepi.resources.linux.ccn.ccnapplication module +---------------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccncat module +-------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccncat + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccncontent module +------------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccncontent + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnd module +------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccnd + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpeek module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpeek + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnping module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpingserver module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpingserver + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnpoke module +--------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.ccnpoke + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.ccnr module +------------------------------------ + +.. automodule:: nepi.resources.linux.ccn.ccnr + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ccn.fibentry module +---------------------------------------- + +.. automodule:: nepi.resources.linux.ccn.fibentry + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.netns.rst b/doc/sphinx/_layout/nepi.resources.linux.netns.rst new file mode 100644 index 00000000..a20d9109 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.netns.rst @@ -0,0 +1,30 @@ +nepi.resources.linux.netns package +================================== + +Submodules +---------- + +nepi.resources.linux.netns.netnsclient module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.netns.netnsclient + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.netns.netnsemulation module +------------------------------------------------ + +.. automodule:: nepi.resources.linux.netns.netnsemulation + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.netns + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.ns3.ccn.rst b/doc/sphinx/_layout/nepi.resources.linux.ns3.ccn.rst new file mode 100644 index 00000000..a6e08684 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.ns3.ccn.rst @@ -0,0 +1,70 @@ +nepi.resources.linux.ns3.ccn package +==================================== + +Submodules +---------- + +nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication module +----------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccncatdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccndceapplication module +-------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccndceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnddceapplication module +--------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnddceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication module +------------------------------------------------------------ + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnpeekdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication module +------------------------------------------------------------ + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnpokedceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication module +--------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3ccnrdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication module +------------------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ccn.ns3fibentrydceapplication + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ns3.ccn + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.ns3.rst b/doc/sphinx/_layout/nepi.resources.linux.ns3.rst new file mode 100644 index 00000000..341946ed --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.ns3.rst @@ -0,0 +1,69 @@ +nepi.resources.linux.ns3 package +================================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.linux.ns3.ccn + +Submodules +---------- + +nepi.resources.linux.ns3.fdudptunnel module +------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.fdudptunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3client module +----------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3dceapplication module +------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3dceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3pingdceapplication module +----------------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3pingdceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.ns3simulation module +--------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.ns3simulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ns3.tuntapfdlink module +-------------------------------------------- + +.. automodule:: nepi.resources.linux.ns3.tuntapfdlink + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.linux.rst b/doc/sphinx/_layout/nepi.resources.linux.rst new file mode 100644 index 00000000..40e4309b --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.linux.rst @@ -0,0 +1,167 @@ +nepi.resources.linux package +============================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.linux.ccn + nepi.resources.linux.netns + nepi.resources.linux.ns3 + +Submodules +---------- + +nepi.resources.linux.application module +--------------------------------------- + +.. automodule:: nepi.resources.linux.application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.channel module +----------------------------------- + +.. automodule:: nepi.resources.linux.channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.debfuncs module +------------------------------------ + +.. automodule:: nepi.resources.linux.debfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.gretunnel module +------------------------------------- + +.. automodule:: nepi.resources.linux.gretunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.interface module +------------------------------------- + +.. automodule:: nepi.resources.linux.interface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.mtr module +------------------------------- + +.. automodule:: nepi.resources.linux.mtr + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.node module +-------------------------------- + +.. automodule:: nepi.resources.linux.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.nping module +--------------------------------- + +.. automodule:: nepi.resources.linux.nping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.ping module +-------------------------------- + +.. automodule:: nepi.resources.linux.ping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.route module +--------------------------------- + +.. automodule:: nepi.resources.linux.route + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.rpmfuncs module +------------------------------------ + +.. automodule:: nepi.resources.linux.rpmfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tap module +------------------------------- + +.. automodule:: nepi.resources.linux.tap + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tcpdump module +----------------------------------- + +.. automodule:: nepi.resources.linux.tcpdump + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.traceroute module +-------------------------------------- + +.. automodule:: nepi.resources.linux.traceroute + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tun module +------------------------------- + +.. automodule:: nepi.resources.linux.tun + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.tunnel module +---------------------------------- + +.. automodule:: nepi.resources.linux.tunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.udptest module +----------------------------------- + +.. automodule:: nepi.resources.linux.udptest + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.linux.udptunnel module +------------------------------------- + +.. automodule:: nepi.resources.linux.udptunnel + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.linux + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.netns.rst b/doc/sphinx/_layout/nepi.resources.netns.rst new file mode 100644 index 00000000..eacf7f36 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.netns.rst @@ -0,0 +1,118 @@ +nepi.resources.netns package +============================ + +Submodules +---------- + +nepi.resources.netns.netnsapplication module +-------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsbase module +------------------------------------- + +.. automodule:: nepi.resources.netns.netnsbase + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsclient module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsclient + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsemulation module +------------------------------------------ + +.. automodule:: nepi.resources.netns.netnsemulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsinterface module +------------------------------------------ + +.. automodule:: nepi.resources.netns.netnsinterface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsipv4address module +-------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsipv4address + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsnode module +------------------------------------- + +.. automodule:: nepi.resources.netns.netnsnode + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsnodeinterface module +---------------------------------------------- + +.. automodule:: nepi.resources.netns.netnsnodeinterface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsroute module +-------------------------------------- + +.. automodule:: nepi.resources.netns.netnsroute + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsserver module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsserver + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnsswitch module +--------------------------------------- + +.. automodule:: nepi.resources.netns.netnsswitch + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnswrapper module +---------------------------------------- + +.. automodule:: nepi.resources.netns.netnswrapper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.netns.netnswrapper_debug module +---------------------------------------------- + +.. automodule:: nepi.resources.netns.netnswrapper_debug + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.netns + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.ns3.classes.rst b/doc/sphinx/_layout/nepi.resources.ns3.classes.rst new file mode 100644 index 00000000..e489b712 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.ns3.classes.rst @@ -0,0 +1,862 @@ +nepi.resources.ns3.classes package +================================== + +Submodules +---------- + +nepi.resources.ns3.classes.aarf_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aarf_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.aarfcd_wifi_manager module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aarfcd_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.adhoc_wifi_mac module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.adhoc_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.aloha_noack_net_device module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.aloha_noack_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.amrr_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.amrr_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ap_wifi_mac module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ap_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.arf_wifi_manager module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.arf_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.arp_l3protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.arp_l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.base_station_net_device module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.base_station_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.binary_error_model module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.binary_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.binary_error_sixlow_model module +----------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.binary_error_sixlow_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bridge_channel module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.bridge_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bridge_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.bridge_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.bulk_send_application module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.bulk_send_application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.burst_error_model module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.burst_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.cara_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.cara_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_acceleration_mobility_model module +---------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.constant_acceleration_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_position_mobility_model module +------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_position_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_rate_wifi_manager module +------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_rate_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_speed_propagation_delay_model module +------------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_speed_propagation_delay_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.constant_velocity_mobility_model module +------------------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.constant_velocity_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.cost231propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.cost231propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.csma_channel module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.csma_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.csma_net_device module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.csma_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.drop_tail_queue module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.drop_tail_queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.dsrdsr_routing module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.dsrdsr_routing + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.emu_net_device module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.emu_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_channel module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.error_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_channel_sixlow module +------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.error_channel_sixlow + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.error_net_device module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.error_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.fd_net_device module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.fd_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.fixed_rss_loss_model module +------------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.fixed_rss_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.friis_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.friis_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.gauss_markov_mobility_model module +------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.gauss_markov_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.hierarchical_mobility_model module +------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.hierarchical_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model module +------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.hybrid_buildings_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.icmpv4l4protocol module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.icmpv4l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.icmpv6l4protocol module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.icmpv6l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ideal_wifi_manager module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ideal_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ipv4l3protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.ipv4l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.itu_r1411los_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model module +----------------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.itu_r1411nlos_over_rooftop_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.jakes_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.jakes_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model module +------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.kun2600mhz_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.list_error_model module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.list_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.log_distance_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.log_distance_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.loopback_net_device module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.loopback_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lr_wpan_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lr_wpan_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_enb_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_enb_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_simple_net_device module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_simple_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.lte_ue_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.lte_ue_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.matrix_propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.matrix_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.mesh_point_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.mesh_point_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.mesh_wifi_interface_mac module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.mesh_wifi_interface_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.minstrel_wifi_manager module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.minstrel_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.multi_model_spectrum_channel module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.multi_model_spectrum_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.nakagami_propagation_loss_model module +----------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.nakagami_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.nist_error_rate_model module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.nist_error_rate_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.node module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.non_communicating_net_device module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.non_communicating_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ocb_wifi_mac module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ocb_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.oh_buildings_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.oh_buildings_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.okumura_hata_propagation_loss_model module +--------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.okumura_hata_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.on_off_application module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.on_off_application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.onoe_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.onoe_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.packet_sink module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.packet_sink + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.ping6 module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.ping6 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_channel module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_net_device module +----------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.point_to_point_remote_channel module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.point_to_point_remote_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.radvd module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.radvd + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_direction2d_mobility_model module +------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_direction2d_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_propagation_delay_model module +---------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_propagation_delay_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_propagation_loss_model module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_walk2d_mobility_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_walk2d_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.random_waypoint_mobility_model module +---------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.random_waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.range_propagation_loss_model module +-------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.range_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.rate_error_model module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.rate_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.receive_list_error_model module +---------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.receive_list_error_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.red_queue module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.red_queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.rraa_wifi_manager module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.rraa_wifi_manager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.simple_channel module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.simple_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.simple_net_device module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.simple_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.single_model_spectrum_channel module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.single_model_spectrum_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.six_low_pan_net_device module +-------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.six_low_pan_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.sta_wifi_mac module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.sta_wifi_mac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model module +----------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.steady_state_random_waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.subscriber_station_net_device module +--------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.subscriber_station_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.tap_bridge module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.tap_bridge + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.tcp_l4protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.tcp_l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.three_log_distance_propagation_loss_model module +--------------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.three_log_distance_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model module +----------------------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.two_ray_ground_propagation_loss_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.uan_channel module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.uan_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_client module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_echo_client module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_echo_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_echo_server module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_echo_server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_l4protocol module +------------------------------------------------ + +.. automodule:: nepi.resources.ns3.classes.udp_l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_server module +-------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.udp_trace_client module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.udp_trace_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.v4ping module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.v4ping + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.virtual_net_device module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.virtual_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.waypoint_mobility_model module +--------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.waypoint_mobility_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.wifi_net_device module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.wifi_net_device + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_error_rate_model module +------------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_error_rate_model + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_wifi_channel module +--------------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_wifi_channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.classes.yans_wifi_phy module +----------------------------------------------- + +.. automodule:: nepi.resources.ns3.classes.yans_wifi_phy + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.ns3.classes + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.ns3.rst b/doc/sphinx/_layout/nepi.resources.ns3.rst new file mode 100644 index 00000000..94356ab8 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.ns3.rst @@ -0,0 +1,269 @@ +nepi.resources.ns3 package +========================== + +Subpackages +----------- + +.. toctree:: + + nepi.resources.ns3.classes + +Submodules +---------- + +nepi.resources.ns3.ns3application module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3arpl3protocol module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3arpl3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3base module +--------------------------------- + +.. automodule:: nepi.resources.ns3.ns3base + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3ccndceapplication module +---------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3ccndceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3channel module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3client module +----------------------------------- + +.. automodule:: nepi.resources.ns3.ns3client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3dceapplication module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3dceapplication + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3dcehelper module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3dcehelper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3errormodel module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3errormodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3errorratemodel module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3errorratemodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3fdnetdevice module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3fdnetdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3icmpv4l4protocol module +--------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3icmpv4l4protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3ipv4l3protocol module +------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3ipv4l3protocol + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3mobilitymodel module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3mobilitymodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3netdevice module +-------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3netdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3node module +--------------------------------- + +.. automodule:: nepi.resources.ns3.ns3node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3pipechanel module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3pipechanel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3propagationdelaymodel module +-------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3propagationdelaymodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3propagationlossmodel module +------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3propagationlossmodel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3queue module +---------------------------------- + +.. automodule:: nepi.resources.ns3.ns3queue + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3route module +---------------------------------- + +.. automodule:: nepi.resources.ns3.ns3route + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3server module +----------------------------------- + +.. automodule:: nepi.resources.ns3.ns3server + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3simulation module +--------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3simulation + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifichannel module +---------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3wifichannel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifimac module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifimac + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifinetdevice module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifinetdevice + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifiphy module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wifiphy + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wifiremotestationmanager module +----------------------------------------------------- + +.. automodule:: nepi.resources.ns3.ns3wifiremotestationmanager + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wrapper module +------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wrapper + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.ns3wrapper_debug module +------------------------------------------ + +.. automodule:: nepi.resources.ns3.ns3wrapper_debug + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.ns3.resource_manager_generator module +---------------------------------------------------- + +.. automodule:: nepi.resources.ns3.resource_manager_generator + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.omf.rst b/doc/sphinx/_layout/nepi.resources.omf.rst new file mode 100644 index 00000000..7dd222ee --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.omf.rst @@ -0,0 +1,118 @@ +nepi.resources.omf package +========================== + +Submodules +---------- + +nepi.resources.omf.application module +------------------------------------- + +.. automodule:: nepi.resources.omf.application + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.channel module +--------------------------------- + +.. automodule:: nepi.resources.omf.channel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.interface module +----------------------------------- + +.. automodule:: nepi.resources.omf.interface + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.messages_5_4 module +-------------------------------------- + +.. automodule:: nepi.resources.omf.messages_5_4 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.messages_6 module +------------------------------------ + +.. automodule:: nepi.resources.omf.messages_6 + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.node module +------------------------------ + +.. automodule:: nepi.resources.omf.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf5_api module +---------------------------------- + +.. automodule:: nepi.resources.omf.omf5_api + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf6_api module +---------------------------------- + +.. automodule:: nepi.resources.omf.omf6_api + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf6_parser module +------------------------------------- + +.. automodule:: nepi.resources.omf.omf6_parser + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_api_factory module +----------------------------------------- + +.. automodule:: nepi.resources.omf.omf_api_factory + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_client module +------------------------------------ + +.. automodule:: nepi.resources.omf.omf_client + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.omf_resource module +-------------------------------------- + +.. automodule:: nepi.resources.omf.omf_resource + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.omf.wilabt_node module +------------------------------------- + +.. automodule:: nepi.resources.omf.wilabt_node + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.omf + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.planetlab.ns3.rst b/doc/sphinx/_layout/nepi.resources.planetlab.ns3.rst new file mode 100644 index 00000000..a8759d48 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.planetlab.ns3.rst @@ -0,0 +1,30 @@ +nepi.resources.planetlab.ns3 package +==================================== + +Submodules +---------- + +nepi.resources.planetlab.ns3.fdudptunnel module +----------------------------------------------- + +.. automodule:: nepi.resources.planetlab.ns3.fdudptunnel + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.ns3.tuntapfdlink module +------------------------------------------------ + +.. automodule:: nepi.resources.planetlab.ns3.tuntapfdlink + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab.ns3 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.planetlab.openvswitch.rst b/doc/sphinx/_layout/nepi.resources.planetlab.openvswitch.rst new file mode 100644 index 00000000..edbb21a2 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.planetlab.openvswitch.rst @@ -0,0 +1,30 @@ +nepi.resources.planetlab.openvswitch package +============================================ + +Submodules +---------- + +nepi.resources.planetlab.openvswitch.ovs module +----------------------------------------------- + +.. automodule:: nepi.resources.planetlab.openvswitch.ovs + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.openvswitch.ovsport module +--------------------------------------------------- + +.. automodule:: nepi.resources.planetlab.openvswitch.ovsport + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab.openvswitch + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.planetlab.rst b/doc/sphinx/_layout/nepi.resources.planetlab.rst new file mode 100644 index 00000000..9fde12c9 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.planetlab.rst @@ -0,0 +1,70 @@ +nepi.resources.planetlab package +================================ + +Subpackages +----------- + +.. toctree:: + + nepi.resources.planetlab.ns3 + nepi.resources.planetlab.openvswitch + +Submodules +---------- + +nepi.resources.planetlab.node module +------------------------------------ + +.. automodule:: nepi.resources.planetlab.node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.plcapi module +-------------------------------------- + +.. automodule:: nepi.resources.planetlab.plcapi + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.sfa_node module +---------------------------------------- + +.. automodule:: nepi.resources.planetlab.sfa_node + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.tap module +----------------------------------- + +.. automodule:: nepi.resources.planetlab.tap + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.tun module +----------------------------------- + +.. automodule:: nepi.resources.planetlab.tun + :members: + :undoc-members: + :show-inheritance: + +nepi.resources.planetlab.vroute module +-------------------------------------- + +.. automodule:: nepi.resources.planetlab.vroute + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.resources.planetlab + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.resources.rst b/doc/sphinx/_layout/nepi.resources.rst new file mode 100644 index 00000000..4c1fcfc2 --- /dev/null +++ b/doc/sphinx/_layout/nepi.resources.rst @@ -0,0 +1,22 @@ +nepi.resources package +====================== + +Subpackages +----------- + +.. toctree:: + + nepi.resources.all + nepi.resources.linux + nepi.resources.netns + nepi.resources.ns3 + nepi.resources.omf + nepi.resources.planetlab + +Module contents +--------------- + +.. automodule:: nepi.resources + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.rst b/doc/sphinx/_layout/nepi.rst new file mode 100644 index 00000000..aa1d5d30 --- /dev/null +++ b/doc/sphinx/_layout/nepi.rst @@ -0,0 +1,20 @@ +nepi package +============ + +Subpackages +----------- + +.. toctree:: + + nepi.data + nepi.execution + nepi.resources + nepi.util + +Module contents +--------------- + +.. automodule:: nepi + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.util.parsers.rst b/doc/sphinx/_layout/nepi.util.parsers.rst new file mode 100644 index 00000000..34888c17 --- /dev/null +++ b/doc/sphinx/_layout/nepi.util.parsers.rst @@ -0,0 +1,22 @@ +nepi.util.parsers package +========================= + +Submodules +---------- + +nepi.util.parsers.xml_parser module +----------------------------------- + +.. automodule:: nepi.util.parsers.xml_parser + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.util.parsers + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/_layout/nepi.util.rst b/doc/sphinx/_layout/nepi.util.rst new file mode 100644 index 00000000..cf0bc639 --- /dev/null +++ b/doc/sphinx/_layout/nepi.util.rst @@ -0,0 +1,141 @@ +nepi.util package +================= + +Subpackages +----------- + +.. toctree:: + + nepi.util.parsers + +Submodules +---------- + +nepi.util.environ module +------------------------ + +.. automodule:: nepi.util.environ + :members: + :undoc-members: + :show-inheritance: + +nepi.util.execfuncs module +-------------------------- + +.. automodule:: nepi.util.execfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.guid module +--------------------- + +.. automodule:: nepi.util.guid + :members: + :undoc-members: + :show-inheritance: + +nepi.util.logger module +----------------------- + +.. automodule:: nepi.util.logger + :members: + :undoc-members: + :show-inheritance: + +nepi.util.manifoldapi module +---------------------------- + +.. automodule:: nepi.util.manifoldapi + :members: + :undoc-members: + :show-inheritance: + +nepi.util.netgraph module +------------------------- + +.. automodule:: nepi.util.netgraph + :members: + :undoc-members: + :show-inheritance: + +nepi.util.parallel module +------------------------- + +.. automodule:: nepi.util.parallel + :members: + :undoc-members: + :show-inheritance: + +nepi.util.plotter module +------------------------ + +.. automodule:: nepi.util.plotter + :members: + :undoc-members: + :show-inheritance: + +nepi.util.rmatcher module +------------------------- + +.. automodule:: nepi.util.rmatcher + :members: + :undoc-members: + :show-inheritance: + +nepi.util.serializer module +--------------------------- + +.. automodule:: nepi.util.serializer + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sfaapi module +----------------------- + +.. automodule:: nepi.util.sfaapi + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sfarspec_proc module +------------------------------ + +.. automodule:: nepi.util.sfarspec_proc + :members: + :undoc-members: + :show-inheritance: + +nepi.util.sshfuncs module +------------------------- + +.. automodule:: nepi.util.sshfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.statfuncs module +-------------------------- + +.. automodule:: nepi.util.statfuncs + :members: + :undoc-members: + :show-inheritance: + +nepi.util.timefuncs module +-------------------------- + +.. automodule:: nepi.util.timefuncs + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nepi.util + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py new file mode 100644 index 00000000..188ce2ae --- /dev/null +++ b/doc/sphinx/conf.py @@ -0,0 +1,247 @@ +# -*- coding: utf-8 -*- +# +# Nepi documentation build configuration file, created by +# sphinx-quickstart on Tue Mar 25 16:32:00 2014. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../../src')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'NEPI' +copyright = u'2014, Alina Quereilhac, Lucia Guevgeozian Odizzio, Julien Tribino' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '3' +# The full version, including alpha/beta/rc tags. +release = '3.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'sphinxdoc' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Nepidoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'NEPI.tex', u'NEPI Documentation', + u'Alina Quereilhac, Lucia Guevgeozian Odizzio, Julien Tribino', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'NEPI', u'NEPI Documentation', + [u'Alina Quereilhac, Lucia Guevgeozian Odizzio, Julien Tribino'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'NEPI', u'NEPI Documentation', + u'Alina Quereilhac, Lucia Guevgeozian Odizzio, Julien Tribino', + 'NEPI', 'The network experimentation programming interface', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst new file mode 100644 index 00000000..6cc4c839 --- /dev/null +++ b/doc/sphinx/index.rst @@ -0,0 +1,91 @@ +.. Nepi documentation master file, created by + sphinx-quickstart on Tue Mar 26 11:36:35 2013. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +NEPI modules +============ + +This page documents the NEPI source code. It presents the NEPI core modules, the Platform resource modules (i.e. drivers to manage platforms), and other miscellaneous classes. + +Core modules +------------ + + * ExperimentController API + + * :mod:`ExperimentController ` + + * ResourceManager API + + * :mod:`ResourceManager ` + + * Attribute module + + * :mod:`Attribute ` + + * Trace module + + * :mod:`Trace ` + + * Runner module + + * :mod:`ExperimentRunner ` + + * Scheduler module + + * :mod:`Scheduler ` + + + +Platform modules +---------------- + + * Live Experiments + + * Linux testbeds + + * :mod:`Linux ` + + * PlanetLab testbeds + + * :mod:`PlanetLab ` + + * OMF testbed + + * :mod:`OMF ` + + * Simulated Experiments + + * ns-3 simulator + + * :mod:`ns-3 ` + + * :mod:`ns-3 in Linux hosts ` + + * Emulated Experiments + + * DCE emulation extension + + * :mod:`DCE Application ` + + * :mod:`DCE Linux Application ` + + * NetNS emulator + + * :mod:`NetNS ` + +Miscellaneous modules +--------------------- + + * :mod:`Util ` + +.. toctree:: + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + -- 2.51.1