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

#O93S_Cdfj$L&ko`+2rC$Ni5+ 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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_ 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 wUl;Tm282}~5u-pvrWcyBHq)$ 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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

S$tLr_yAI-~*oxuScML)CejYUJGQVfv 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 W)ARnE1~p2Pf9yI7t@o?Z;Qk+BP_rNa literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.planetlab.doctree new file mode 100644 index 0000000000000000000000000000000000000000..6f56c3180c07d740b0065fd9e5ca5e254bc4fe14 GIT binary patch literal 143676 zcmeFab$A;`_dTvO>?CDI6=SD?GNjCqG)>#6b-{IId!5xrmaLH!C#}^cMJHuuW@ct) z<~C(`3odh0_&w*`+1*)b1)9`qsw=r{Wz}ZhEJc&Gai|`qwwEABjX#R%c?gva;#CYPGVX zJCpI0l}pB3Mt3G#jT=;Q28q!VU91T> zYL6$9&7H}3XCgDOr*Xqd-cwaNpELaTl;gH^b2gXm%na&jtcye<*?db!x-FlyvYEjX z8aJv0n2UG%Y$nA!N9Q|}>3CbS&N@@q(>SJ*e>kDckeW zN&?8OIhD>e$EU^<$#_fB$}H5=xK1U+AQ`V$S#6nxdm6`9@(gbSbP8o9t$5bTEYj1s zc_oDM*|ep-#>gz%(^y{%N>n;uX0ZvChe9ypcw3v)Ju5GpS-hul?Ml&t-jl7IcxN+9 zR2f4-$9&4GY8k*w_B5{d&*HMN6RGxeW~rXWZ7cbfX(@Ni<>D&W+?wv_h^N{zOZPOc zQ3)%MMrN5ReWYZZOpPZKZSF`(q*Iw?dm5t^;zc{-tyAKYt;}*0Dv!tjFSbh}m9tcP zyw%EPmhWjCSs_S~a|d)bvqDd02@C27MWij=+^N!26Imp-Vo&21m10)x{65S|Rk~Ga z4JX>0F|RbYCz4hsT1ChL)wX@SHJ4V?S$n90m8(oD0cU?K=#jKaPh&%+3drSC#vG7O zWmc`C-XS&4IShhlrPBGywvN1772PSRv(S;SdQam*kw`>TCEA)!<*ZaLn^|K*<+(Cg zDeZ|=B5OBy$)h}jY%>Rfc_urgX&|PY*!upN%{D!aqbgNJpds{vAhT^1?mA(?FWKTnz+mrFB>AcG9T;-gtY;|YG zRaqdE37m^h&Su8b)K0}#U;o*XJvDlUH{Qi%9kT%JMkaY zRLaVArPY*XxmdGXl_|0`z0t{Z>y*syJ&oH}s+RIKTqNNXwLPkgr$CLlOZ!%3;c5fc zLzDiA|L8U=X}OmvIOAtxJ&mhX$_BOI&YpWtsO7BEwccw&<)vPkkq5c8I+N+?nZ}-c zY>{lfC7Vm+@;J?GZnN66nY{~{ePRoC##Pp8?y$1i_+%@a*|#aPUu?nFyi!&wr!PQd znkK~R+N{>Jit{9O{|T{0_(x?V1QuDYzv4J?(O0;D&2NW{#dV7F9z#eE1 zvz){`>z){)u_$XBBD1D)$)n43Q++M<7!d}u|(q775%3j)D+Fr(9#$MK5)?O|a zEsNxyRJYm7+soT4*elp8+AG>C*(=#mJ8G|NuWYYkuVSxiuWGMmuV$}quWqjqTS%gg z@=k;-d$>K^uD9#$2D`x?VUMuawAZvp+9T~z_9%O_J=z{)kFnRX*Rt1+ty-2!F5c

P)9u(zbI*PADXRTIr>AFm+ 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 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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 i%GUSw*Ek$qQ-=k$+B%#p^NUyK(^J2OZF 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

fPLQ_}s54X{dy>xM-{f>OI`*j`PVZtYvrg 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Ȓ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¨%4R8XW*PWh6@4NAezNB9!6 zby6ajmGb$ig;L5Qjv00|5cb<{I}u+>qRA9c*3`e0x)W3i)Xt_lzZrJV)zRvZ;Y`#=A>`Rwrq@nPgprAsPQsyXvMLChgfSh*31$YWyS*bRojRiDH z2k6nHU#RkhSrFAWX~2cC_=Vgm1a}QgpYc+i6jlpWpkpJqMR(NSIfOtudpzd3rZU(i^_}E=1V_CrjZMp zP@0YuOn-t`R3bJyPWY!P!KH$;NWn}@SL!w2?{HbyQ43` z)XoKEk-1gH^}ni272k5##HoWyAso8f_S80Ym%m~$?9VAJ>bRfFWiqP}m>1xaexWuO zW`KU7mW~?sPGTY$N|smE{8d23gQx+bX5esppeo`#{mr zlXY13k`M8RNA=>k- zk2&;C&eDl#`C;k%TWLi@-k2(}WEB>ea z37E~Y)A9!&x8A?Y6)l$K9|lxVM1Cp-dI0Q91CT_?HpcuZY=QpFYf&uHcE!^T;h+)p zKNymOo5~QHoi5(#Ko5s2I_(By+|s+*#MJSQwt~D12R*=*rvif15`fzbM$abD=Nrkd z+)(~1HI}*N8_Tb9*vQ|mxuJrlP>)3niqKHA@xs^N+S@&Av{?B)NfVeUx;spO1eDgLTb(hjMQ=z!%Zd;9Q7FbsQ= zfjf-F#1g^KyzM25kT0Tkkm={`=!V$9+K{yJzom4D$P!(Qj+npp*))p3v;EJ{4?a;< zUkKY){a?5Lw{uG3TWc{~za+yuMV;Xdk3z zC!X*8_v z=hgI(I{|Eqe>UIwSM%owKTtK8(|OqHKR)02Pv&b@7<)x3ZvWc$->)GanSwbZrA6mA z=R5yw{`}ziDo7k|DI$~wfBR>)f0na{mhegyrSt9I?fl@}`N3j!-$erzY1MggzOyku zqnUf|w#_!?JMnxCS^4f3w!zQOb$)T~{NPhn;N=5=Nt5k=zWuv3gzm+pw6%X_`|q3| zd~ZefUV7L@Xa2dGO=)b9q`S`CeCNCBmdZ@fx-!^Czc| zh9HV;)HeE8^E8dh9cre5&0}MJ*oOaNuJbSJ) zDl(L<`diz-jqJSt9UVuN$ge`k;QI8VXmI^P=g;8!MYhi1`qUGr4i-6N2G?is@4@xi z2g%_2W!U=Q`UN=o;QB1)J-AM(k4sbmeqD#*0+X(rn_bjih`IgI3J${rJ-A+dDtpXo zaJ`a4)h(OZ%rhXv>orjHeN~V_B&ma%Hdoz8;>m;S)n`?aHPzKKxU-D1j*11x%zWx- zBB$i9!?x)PGSJ{U<+Uym1*4>L2UoGrx?Lj-VsKp&QGfi(l`C~wc9Xxu38;UK5>WqL zNE!F`kYlnRKQN9yg3-QA6y{YNj;%^hzX8s^JT z+J>X?Fw`(=PLd$XPF39JK02Gbci!CC+2445>;BgMBUriI+uGmR+}l(49_*?O^>AZ% zf9uX$_cwOc!?$)HKG@rAE48QTNr}67W9KdP2H6P>3t6Jc0%wFA4hWwc4%7BkLl=+Y zi9`q(z$P`(T^*7cfI^~Vd0eaSnuiW3x|T5z2w@}_A1A@6t>9iB#YilywR#1<{%bdG zoSdArkE2ODPL6L3!>*1}o!)qrVcM8vgE(1J8^bUP)E6c?(cy3qbk!>Xere-D_mfwzUR_*Vbjj09UTMlH%>QO}1fCB!kOUM@a;IbMa>3fXYq(oZ*j7h$DSMnw z4%)T7{oSpdH&|=)dK?dNlU-Mh*B?B%&p&QPlaWSFHuGh3=dBKZxf@Slv5V?=AH4PY z{Z0NEp}&qbqGdF;cJ?>l*xYRtCqr5J%w*`_ZZh;IHgb0mAa1Zu!msfYBPE^1;sueL z99@8AT0XvL(l+WbWs(hgWZDv@Y7q8%AYP77k64e(to+=GcTtUSa8oU+o76x3&(zLG zaWCv+55RUtV%PV=j7*x3_|b}np{{n~w<%N>PVRE3@7Owa8lO?>U76aVy7^i4>8e@5^9Pn`nNE04 zS*&_t+QrLWVT^lROIF||zx&&_s=EhmVhkj|PQXxL1V{m{VUx7mQ4`93#4a5!Mu{OG zO5`&R5`-Z2DUUwyN|yrAXVs$mY{kNHqAoyTlJG&jDn=XhBueq`sna)x@loJ#_&H$i z*5|KYH9OC8h-Q5B72VB@qKR0Fx5aRV#*{HVPXh?w8H_Y=jZJBRprNrP=^s!s%MHTl zml0RBr3QL9ZV}IdvoTm#o7qxcfh|dZ=qUod1(PA1p!x5>us-uQjVL7vqGR;UHSxqU zh-18%;0I5sCfozXD1XK`hR;1udyGtIoXJEjlJZw(|%@dV*QV2nEI zy5a`tN@igHVY&o^=S1=N7s)nVJQRZrb3iipE1OwR*&861HrPoV(flkxZCVC5DviQ} zR?U!>22<>ZkxpGV>PQcQC&*>VJKI~f&>&5mh>?$)(jr)RxJR!Ur$#jv!i40w@1V8q>_5!FhS=9^2wF1}8`jfKm?j4t zdHL+6P^trmPGg9mMmj*W$o^zVGjXRr!Do9eQip{p7mlb1Ic>!?)f@#+TWSc?&?NO6FasrzCx6Y(TYM1a8zEyPmXK=u=_qs%3YGQ22eWa!)M z591(fDf*9lNN`OF;g$)lse6;COH6?lPtIX;z3x$J9GHKoKt=k*^&^Ez&Kv?I%5$h; zkcIcHslFMOiQ4CU^muj%c7}8(en@@(0`8>NiAmX6@fRYH^*k2&i|}s#Z=9&rLQ}`S z&A$rYg@x093*X#Pz=JVL)@7gB+KUPqa-ojJse6Q=UQc4ULQckU1SvB*7JDDBjZN0Z zsJ35dEWsze{qeEF2rb+E0h4s>+S!yFN!)vIlF>O`C8Q5WHhOFzEJ(B-PIV5N~?|2V&$PNC{B{ z19)xV=hX5IY4Hq-xBt9QGzbuaP*X#-gyx=mhT+iob&Umm<`!f(RVf~DHFrEz;FTb4 z8$NiQA%=-0Msf2(S}j_wS;)QYcBT4m9I!1nPK&!M@TEI()DMp*i8dz>4_P{4a+4*^ zrimEDqoIg3ARiAR;#;{QZ%rXx@Nm{oI7gACPQysO!xsnEM6}E`!kqA5CQ*_YHW5;O z#O5fBT51$LUA7h+xGy;PQ5YPoR~%$b`pYx(F*PWQAb(V^u0y<`fw}D~2%P!UXctiI zN#ae}xUdkYVTv^hduFAIV}^ZhSV*TP$d;2SKUb7R^(JmVMi-WvZ5_;%t@3q%s>xi`TRp50%Z{@N6;)OMzL*d>wx2wwz^2cr?k7Qt^mXblRjMf#M+v zk#rgwMC0xXgX5l;B`fIZuTG#~qgj)FrGl5RX$NLmaS{gUAxScN>M7x~MMef#qG{;7 za78+(0D@MQn?7&I!pa0^$$wAJeBX2B$`y+d+Wz)A@N3(D;{4zb=DyRevlV`P`zOv1 z{!p%h;Q_YFf4Kc)=Ldf{S49p6TjwXX|J?b(clvd_2kn>f=#7UT2c(BT+Xuak=jQ^k zz<&S6_7C&3xa%fQFt+C3-2UZr8lSGA9weXKe)+sG1nAW^9B*eubm8Q%FU{Nk!S;_9 zaUr@E+sO}Y$L9wh%T3qPy{+`;wtu>aceAdx%4GYLXF)92o5dg5{$z0gyPIt5pWgl( zcnJO0$Ce@>|;fL~m*T zGrgt#!gqc2mZr7Zi~HFL5~ANj)?MPiFUwmJ>lFCq2lwq>h}2i$^+;t-;^ZJ6gTDt9 zAy{tmAHAjB=SQ#)$6Fdjkg0oSmQ-GL*SADSgnR`#$YfugxS2hwU^SKy{N!RpdL{BM+5gO@v{|RfT&`%X<4W$+t$`BU|x|%?}br)W^QKVUk=Djs|mLo=Do0)p~jonQd zTM{r|A`7zscau&1$rHuT$6OLrNrsYEw=UWWvv5~AoZ!;MOl1UAv$&G)c9>0p)!D}K z6lIWaq4kA7gK5ee?*+@pt&p-c%YDtQNFh>XGLlP#?vnH&8=*-C&UR1~a@tKH?KhKA zOEr!Y_^Z%TR|U4=>v$ri9kO!c(){(5-)I^Cp{*e}`xwq2re zdk1@MyW{yNxE9s3vCSTC?|D87u93C z(O0h?rdiU56msp+wb8ZSwKuPIuI*jxH?AHgIygcwg+#Zz@o0<`2aSLCOTDk(T0MKA zv5fDDMtJhv_vQ~hd<8?i`la5dn{CJvKeUYBCQ+EBuMXZFy_>!}O5dHN%jo0kqIw&K z+d%@=3xwl-_*6BvM&mfiNK9DsA{?5lDW)w0diMa>07a79qZNuh*1!B@Re*|NIK#E)T2j_9(6js-kWcBI(vKle!p)b z^T|!j3CXmE74Q>C0xo?=ycUvvQUf&&oil+0?Dt{>FyuI++`9lyQ9upYWC~piEgPMX zX*5qTG$F1z>`8Z$kmVx*5ORcTZbC?qNgA;dwcHzv0h$Aqut?`21MAlZIW&osWyTcM zg!}NHhS3+%j#(KS08Rj;j{=T241RYwr``>25lDp)dy}po`c~DjVZW~vjZDr>g5joG zq5s}e%M#%=2N++WP6i0@2AFTsqatDA7Tw?r6G<75Ib?d!+u<1ILmcK=oCU)}6HBI< z^_I<}qG{I5dhJozO=43+eVTr9e`URP4~d*#RJT5(UR1X~ySlopUQ{>rXP4Ct{Kvx& z0?p7g>QRKJd79r;T#>GUqTjq97{XAnT`DgjA<|%?0$XTcIYMwG+so|09`dr3x7j6G z1aFUh3JT`zK28YzW@CMc7&t%kz zl#uyNz_BFFG8iKa8c)>h-1^gs@ZJVU{7aY`vtJr5x3#4y*}TJd2?qZ`N~v^c{wA)u zSbKt3uL%pJzqnIl)ybdfKg^lHI%w2IwPQFTMf!(sA)6$Tg$8Xbz9k?mesqk_wD1|< zqT29R+G3K?ia7Q-wcDd0>ke{f6pHDuaE1xEyFL}`TpcwKQ0AW1;l)kd#+~O%nO($L1iO zBS7wG@S4*RdcQ^{8Nv3CanO?k0;ifa8yhNWlroFD3nE#76S65e;b67|{ zLYslfLXU({T6+}x4>`NB;R}mo_@Ph8D25(o7t^xk&UcvV^Cj3*KLr%|ic>w+-N85IU42=!3G!f(wxjfR+t~QDgJgU-ygg3hEbhj`;|Q>XES1cpSrhijAj_C}nrKiMfi(Ne~9 ziibGRq%F1a73&=(p-@lZ+Hy+;#=mwvA)URZ%NM%3_mPg_+e*jaJt*^|LKsJFXMAU_ z*_U}MC%1TMxSs@FSZd-w=%jKu*=^EjSF@XYhn%~UR^hqb1q+mlcpI;Nc*pjQ(%V5Y zb{kiQ+1b1OdXVakWPJbjL$j$>^%MBc-tAnqW>s5r7`fN*D80S5mTPBZ#n*_Vc!9@p zX?M|WEc(-CcbJ-Pb7wDV9RC08z1edlNqQfM+2t`Tkt5~{V60AfPjzS&i zM$e!DR5zFf6b3+bqggB^0}-B?K8TEn4v)mq)Ag`s66%MHT&B`l(iYpQ}N{(2YdI`p^R)2n1L_V@;mL3~3mQ&nZH((@T8B*7x^J z%+e-1i2D|lC;IfdjN~HldGzBj6gVwplYMYutPGWQ0QrPM#hOz$cv|+5XN0VAG*$sQ znklUg7&u5aFgOq5{`{$z3gv98tp^rJ02w!IWtcq1_0ZTst}!)nk5!lZ)Z@px!zVi; zT3cu?e6i!5uPrV#7oOG{4o`$)XgJwP(dDL4$a)N!j9~TGv_7I==nqz&be|PN>4ZhH z3#UH3K;~}TQ2fb+#YfwBiZ^?#q|XL?pcJv5iWb-rKJz`l2U~?Ky=b}t$%}&|1ncO_4vDr;n=EpS*D3cK z<#1{$w0C(cE6d?IYe`wREiI=@kCNt19*bk%OOyHhK$%zRYN#449Bw>I|3l(o5NoO2 zpYy2nR_m^ctW&OIk+H1NZB#`(j^U~)?+TgmG@t#P3wyhDQ-w|%(@agc?Wxha4JPbA z`ebUV693*G%I81$`r*_R#knb2A;$eqv(F{`qGkI|`X4I}>5qv+`V-=i{@w4qVh(Bf znnMy{2yM!>5#sA)gg8w{I?C@3Lct?;n2KW&#q7Nw(BDlMmWn8LV}Ov|;(0%8@(gUW zX1@HbkR#s1A-;K%Z5%Fjck3*+Z1!II;_u0iQvw$2lt3SiE*H!ZBk2)~hc zPS>&n%3vPF8DGsK1e0MdjRtHADf1{O1~`XDI}g}O^ERv`NiZW;04m2AHx2o9`CwEA z5!$I9tlDnq>TuXC^DKa3F?K%|%|yt1vCY+FX;UK%ug$}(foVmG`o8S83qd~dTCp8T zo@UIWw4H;5X&CCY!i$*DSfjZ8bBc|yb=cG^q;9&)3CzO`7UcCB^`@rm?%-^uP0(%ClPyuoyE!eamZN zoVH@cE&*{?l_L}og7B{ERQ*C^hRU^YFgP~Lp*SD;tio4PPl{69;}4n=b2_ME z7LTc{=aOpX&`=A=L95BnbF|BAhgOXUCajqgeo^gqHGY#^uL~z8$&0QFGvCe}*hN@1 zn|{h+VrRk(>%}(AWYsJl!lBpr2@w4Kk$x^d8*T+=Y&zf z2|@*A3eU4jVyD4QJw=z0)AcGKSPk|ndmM>#c4#!(B?wNv3MlY`lzA)>?G!17B7Eq2 zh4>zt&T6Vwt%13oy1FNEdqL8t>o^BprjZN4BJZx%#JdP%56;C(>XSd>h=hmI(!Y!kwwU-*p(NWL~7ntt4QIn}(Ysl2UTvYeF+!Yta8WlDx{#ndA(bDo8&BGQf|#<|K%!Sw=1|Ipr+{o#WPykfylSP#nRk z3$v&w%FC4qe#?cJlLSTO4zj~J3%yr24g&US20)<7n3o^9P$~#sy{HVyU9AQR*jM~U zsuAqa<_W)$hLLxR=rAEE_GaXBDCIs!R7@{YjngyZS#5;)dslThn5W}q0h*X|BSOBj%G8R6&2yvBYFroS_vs&WUgYZ_A<7=QPf`an{c`y!^w_r zdf79}hYm+T6qsAhUo)Vt)_NH{)VsLoo=_(8SoU>fST&RXq@!rQfNmy-LBgh0&g9<} zY?4JQwKI85f}krxv6BCyVAx}Rh*!&N5)7we6&xRrFS!mYPDM9DByPjNmY`AfDmXM{ ztEAv9YMitlEht0M4GOTJmC5UA{=_mb7*4L2QLEr(jyO9s{Rm|{suq576^(63FG$tR z6bsoXt7>f1%uBl*%IgY&$h7tGIO2<7E^lUDFvheZ!qysEU2Z!}ysS6AyZolBHBj5> zwtQHay{*%vUv_h+T(&8aozlY64SFS=tVzpmR%d=C>lc#OSt;x6#FtR1DjK?b))2)Q zwBrYgqg;ImUt!iuEX?>_tMwV)q-uP_&k6V9r1UhsK43G6sT7UNZ=+`TVsSWom z-eASE^K|TW`Ih(@{-}W9+R{60lMS z!}H!-H=YK~@ty`@94Clj-i~t(t1N%Wgr?{Wb)~ zMoV~z$US7poyAOEM1C)gBP4%RS@q%$+wh|eSk7l3@i5`3lDB<7YWwuHO|gI0^6@kQ zvaa;%ZKoarh4ZvM7+8gu68eS%>sL1-vqr~=#RPBQVW&BwpQ0jQTuq}IkfJ|8RE{{( z(o4No8owjYYf*I^Ts1^xavRCaLk`A_x0UT-c|@h_S_jM=QJH)NwYC)hwgNQKCE!gW zGGA};f6xtf{4t{(!jbaPB049a%NHGovIhQcS{+nvq~$Xu9{MVS75fD zb_ejQkhM8&k?)qT5|gdyRHShPWPY5u9PsP|5qaqaf|p`nQe5U^^$Bq>hNj^wBGLiR z4l>U_IS`*iGn(Tj?bk~5JTt>)r_q4ySLZA+MRf8;!>bbo#$jIC#kTBw36iHEmX=5w zdBdhmLXp*L@7Cs=1Fu}JN;_Mqp|g`Nx8_Z$tp|Zw`87hibV#7^d_fjS=X|dwo>O5o z`FM0%K|ZJHnRHJscExTftV>TO7fSYI0)`;@P**w zNZu&)V_}+f^`Y&GB08!;_4E+DIHf8Tb3}j*rN=LC6cv*hZ*L72`1B8iIT9f^FviUm zN*McIsGs^+ESvae^9Qj|UJ~w2VM29}IriORU?Iqk6N#GM39AWb%8M={l$TmaRIr*J zh!Dr1rHv)-1aCyn6Vk*U-s^sa$bHm)mK^uL!?E%inMS4z30r zQ+|BptTjqB8Qv&l6=E<&p|MYxeLJECt9{6Eb1#&Zk$ZKRyk@n7%u6%)I#uoSGR-5o z+=iDceTV$fU=9G6?{dIi4vRQ>IV5!ZA`S*9B3L|2|0O9RZz;uHrSLt1X|hjd)2;gR zqxv`iC85r?yotbHzcHqzqs;sk>NdvIZMKJHP1{qwbrVX;|MEo#+xv7Zp1n`a+uB04 ze$zzpiiFJClwzQrLL{bOH0i%miq8Lv6rKOIQgmLwu3alS-zY`rtJhf4yM)m&z9zxE zXzya{sxVUe%}_tFQ55lgFXKBDV``+1b5}?eaopB53eF;gAq6L?HHTZjna^#*<52h1 z6~iInNS&u?na8}$)5KJ~xcxVD_9GeR?myHnT#GW6$ zbBVSUk931)>3@q?w~=GYpWW~IwTzo)C`e^6J?&%fd~w(BTK z*M=Qms$s`8TOVY-I9+Ayp@=;8{Q*z82z#E--t+LK`I-IVhCI@zw~5(n{zfiB74GLi zXDd)bIbyi1F}SX)7)QF&*2aO|Pj&Uip$~4nfFP!Tj!gl*fYR#dKZDSbE-vYO&Kyxfhh1H~lb{lqteMMBzSL)4fyJ4bO zE@s^*4M?)jgF|7?|y&sK1ruU;^u)rV>g#FO)D#nwc7zkTrgLb-jdvP%eW7$U5 z`*s?~oh(k;uoU;Y^pM>~HbE_3|IdoY`Co{~`Cp00dGr@wF^_X?yn4;!e5pLnPltHz z>|ku*Dj|C>-{cQtDJO{9+u2|rhsACf%SWd?-B(9N6%ZqXSN&EkiC+QuON!{0Us6tq zg?DBr^mgIF)V4u!e_{tdkGxdGC0`$M@-k7Xx1vFxL!d6gaROC8PLI84Oa$sDrbg{x zaI7oW9wj_lPq`;+Pm6$4FY1D&P(Fcf&`Xq89i7^tpu?#Uaea|pNZ5iEf|_rL>_XX5 z6v?`Y7^9SzK!;I8^OvLRL->S_rRzc83&UEYw!;H4=+_#$$&ZzyhHPbW>bp7Qr!q~VsScRUaw%z`C9&v*pGREK~R@&P|?(T^qi5Dk%X2EpkVJ&#>9udkqahbNy0Q$F&A<$oik0lZ6h53Yi+ zqse%y6+J)NxH1ICnaP^}x&Bh!=SO#60BG4c_ypK}_XPmi7ogHBPOo)>SDgPHuQ*qy zTmHPms#PYDTuwy7Vb;RK^#4$5kpGj^ApaMsLH@xnT&qE@-KnnKsb0YK*C;1VTR)VP z1IUk)3rAODswo|2B$p{YWzlTF`bo*yKjGO(vjJFV?TLhM^t>qIR$rlY6DpTO##8Oo zB3X78vj>6o-IY3}1KZo)+al4%m?oCod7VDA+Tx0iv?W9@eIY4tSrZFrl%tfcRrVt) zct+_uqn^u#W~CF1a+`JtSP%zuT=vI%P*P7w z&h`fpVi=LB3MK6*I=B!JGXZ#KBB%4*3fWT8zG=ag&D5e_hn?eKv|65Ux4mxuWZ|iD z3mXBZo%Urri`z*2HUzG(yaBW!r2+`84)?d#cgU`n2%$^i4~(~ooC@tuP?u#3V6|ZFt|3=IY5`l`eEw1BbEzsdS5?cM zF6EsrIwBd$h)xy3hB{pu*XfOC>HkffH?rbtOEl+PaJcJlw)USNeXFw8uvODnm_0kI@W>dc5*24$_L^?>j2r#cQfm?iAUrs9x* z5aqblm^B~Lhk9*K?OJUsqN+6memv+Z_Gt+3zLx=RD2|)S1^$H_KM6BE4j1=&ZO2v~ zi9VRcqs2utEFJ;-pviL1uJ&m>7#?4jNA$GE_I5v{kxHaI#kKU}V^s!odj*5J%}0k| zQiC{C7(Lkj@bUf@K6ONQkRnWwYPPkZX*p~^2Qtwet77+PYashjs4RNcY{yO2N6DR0 z_Tn?-w)H}3#3ht&>LtAf3%z3=T366E_m}90q6L;01Z`5T(qo^7mEZV=i&sWiMcziQ z+Kl%TSOpci1l54jm#Lqd{gVJy9osqEq5})BaRyQq)>zzcrh^E1|6Et}f>D;4HBG!C z_DKxVm@U^N(wvIV+o5+653;(ZVUot(wOYizEH2qj*_J`-o!ROHG>K({So^jghjF@A zJL`!IPoH+cZoviG)-SUw3kwYrXWMG>)(+D_(Hg7(f+}I%{eDzaez0&t554|z;IY$H zn3k&{HLbxg<<^(9YqaRn?FpDj#3k^ zHXq~TjBF;7tP4SWCq}v{!{GQSBB0kAqubh{7_&gYR-_>T(jGPt2ynzX)~d9%+`ac9 z&MUQrAXp1Ot3y*CdPs|1>)>>&xt@jgV56!zjWz#ES<@irW$t{dG(PZROet$N_n}>v z@gVhiVJ8%4-)yn8@2WbAi+~0M`KnFwJknJc-`G(MpxR7ewj@{OW|dmeJ1v6?SZKjh{7S&F((fZS8Irv5CB z*N}1vuj*+ZK{+G!Y+lk#p-i*&(^v$!Xeix1ld!SPo3QLm_{GZuMRXX^XGy0V*9?x+ zu%a)N9I_;lS5q0oS#lQ<20_0qsvef+FdC6eVvwOaDI- zy}mv*HD#_OM|z!U%{@Q*RWeD{+(Ld=TN&>AtrHc$)v^>MT-o1$r}h2kN59|#aeA0j z&oO^KghlU1#WuYkQMlG(AGrnVw~cU@?;AwVGEShUw-XU{)2XAWslWDbre8anntGQ0 zYe!R4$45KA^ooVOYqQjAVed;7_ME2?E|s6Wn5s@xO2c+&4UZGyK`#vBGY+e?AGcYkAxW9M!v@P$ z#>#kyiUxfol8!rY)AHCc@)twlb<9E4tU*swnx^*hyvOR>8#{Y*>?T`UVD;_2Io&Xf zqb^U!(jIf%<>|-;y>jO@rZ?z1L~8_x!3$_{E$6{qibJg-gbVXB$12giPKZAtkfnB4 zIZkiB?(5dlY?zpFQbkJ>xu$eEU51o#Ifuzl7$p_KUdjy7QZ>yGsgPo8)NA`0PqM)m&_pgM_Exjuhi_ zX>*ZYtej9Ixje6As*11=|N7C?RNXv{st$(VIy)_4-#Sg5Q8s&jrPWcnN-V+-2`a4* zpDKyd)^{Y%w^{;Ejz4oWHANDpt&`jKy*FN%JQ+kwcNP} zkLiVOqx?|5y!HIo>7u%$tV_n@H0i=&&ySX_2&ZJ2PB}oJ#@s!afJ@;ro3(L}CJmr$ zTCcN+`~oh*OZA&ykn7_wNIzB~=-V>kJSbd}0S~-}4DuJm(3Sf1cPz07Ye+ zV)wrRZsXE4$vKV*L4Lywc1ryuV25;1KRqwu3;SPhiYbFxZz7O2QMd0Th=1!U8Lth8pFg)>xuVz7yIX% zDfH~DM&Fn+4`U(Uns#;}HXpBv&RYhY1!8@KDTB4ohwkN0Zdc79V@B zU(q>nn9whD6Ned}SBL!gM4x|&E?ylSc)0IL_Z@p~!ut-lEnLzKtCSwDID9G3p}r0~ zTvdP6#rf^l94^jZ#l@+^4i7iaFG>u%lC@`06t=I#gP=pA{5yLOgVCgA5&_mNYQy1(xRjT@;H#JE}}dz66p;n`S~0MhR_A{ zqaXJZ5%Qo4F6A{8%4P(8eCLNBZ11)=H@2SXpkOf)AzJpqlwttCO)f>(4WXqlE!YOp zrwT}vfys`C&?ao{G;D5c&0_>!Cg99<=3P{heK*dyPMCGM3BYJ82wg#BFLfp<L?bC2AvsB{k}&5$(}eK z@Y77E0W)OLbmozdIjka)$_JYB)%nDbD>$XtH1m>=gl)&#-W$&d7NMYDk zfD|@n+!Ts|K;__3(1qVGx#Oegp(8~gkAgZX*_L*HPqW8#T-n{1#kqSSok5fb)z&wA zO@|ktVe4odHY#Hz* zj4#^xzNo#cUF!6wV(&@HJK`KpG&2E~Wf)(;#Y(MtB*nIrM4``49%Frb>V~FMtY`;^ zhVEod^)-ip2)|BJ*UhP^scP>YF4?eT#&tsq1iG*ZRh5 zedBAVZ*8f|!Yx{C~+k=ef&}J0( zU!u)UUw%bOz5@I5{O#e2%K5^f^g??1L6FRY4VqVMP=!VKZ@N$6g$~Dag>SdM z`~2va)kAinnZpmh)q3#!=&g!6!z%arA&f8&p)=s?0eWLy?#WMajv5bsZ#;^a%wGG_04cxU2oYkVg`A^gb;{0KJw&z9m zMcVL;_CqztINb1+vW;oSzq51?ktZDw(S7x?q*bgvMjX-y8&to(z4y_^926E=I^Yd_ zzkUDqZC3wiV{wkfS&ye@Lh`XZM7w8aeS?MG1y5PxUEnE|_S0CpzsXyoihyMzcjDCN z95WVIVnP>n};wNo)4b%F6QVoKnk@&KmN)h=IP(#Dy?Z41h(A3~i}bBsBM>t9-@8KZ(Qq?u60V+I;Ec=ozgls|1S2v)gfI{sZ`POm1>ntEW3hMXi8l7%F-n{nmS@^}El>fN}R= zLc>ZCU_}`)RyQul06R9ZQYC)nKrO%9+JVq8YpfQld&s4R(Wyx((HzBYNb5>Sm?I(K zcSuM$ybiu{EhM~ALc*(b{4!ox#vHKVR+W2-nQGQqt1`Q2l~b0sFQg=n6dT2`>qAe! z-m%1;lxZidyoF)Y5wr}7Wx9!>z)_yP6z@?(Lm7khM1O00$?Gg@j`_Sv=EiN-O)G)8 zi71>)(xmE9c_~Y|HFf5we3X<=L1#NqPA{rq(G!Ra*GFW|oR~FJCqvK(Jz3C>Cc}hv zGu@TRo2ReL4e-;xO6@?{De%sZJR77)OX23T)C1L-@ydND5Qg~bFFQ5ls&XoPe(9W# zWov&CoyI3zr#>Ypq{Yp&-ZY<+n!2GYW2VIU20UH{d4S$=dP?NeFYmwrM#v zU;{x+kh5=S-#B;aucMMy4wm6MiAQZNidi^e|3(#1O(%p$JI1XYkXw1vjw^+=hW3&iNR>W8?nI*cQB%9Sth0sXY-fqEnnyM zc7GdD%`_iS*`vc_ywzF)C$I?ddt8%T0Drss!jI(gndk_F(^*ni`!Zeax9MtM{R`Jm zbk|RGZ_*RptCYU&9yRx;HJ56z2cg%M4F+2&S; zc4^hk0JUafSlXu?nGk3lW=IR|jzCX&<&`pg7=#kh%RsKWsx@P>kC$*XHlrmt=|p1KBFwbE-Od3Cc_ukteZ z{FLdu#ww`jh|^_+hKxQBC`WJYfM+|giUeiUVmLUoZmb9`KYa-T1z)j;Z>||cxkS$! zair3?TM&)X(fY*n_|#FqUK08N&o)V&SZnArrgBI;?6?6#vyFBW>zprpy^Df0ab({KT|k;b7Si3;2hWeDt471SLS{V8?=@Gfc}L~zEp|`K z(?XtY{SM@rJ47#SwCG}@hSd9%BBYc6X)Jr6QdZ#7kJtpgPbp1r@t0f``rFl#kxA1F z2=sw9tgP*^ajjm;*H%T^fiu|>zgVa*r0d0uRfO(XB{o6pJ!u!@4+!)UlXD+;TKAtH{k&pXP_w}G zyk`S>C?I8p?tRqw&AhSGjTPYYuHJ5~fQNY(I$5X3Tm{=0&uGL^%-hiCwEJGGEs@Jq8+Aoe8YXYniKF0ULYu1Lf( ziM=53Qyz%S5~65kupR^(^!sR12LV$cehP>=Os+CPg$&~}wq57q? z+G^V-l+PK*(l=|DY{kXr6pkRC_rbCU41T+&1Enkir?39S&U!rMtbDp;=fv^%dB#)8 zd@o|hob|ncBOIm25}wYh_$ut!lW@?80@mR?IQIM#eL!IY6YjnpuKai_NEEg53 zCmQsRd5Y;zxl2T|ZY2qrUc~kf51Pv5=hO=a$Q%(W+v1*g%9$5kFy85KpF*NaB(^Wy zfnL~+Q<3%hFDIAYeT~Cd=^3b+n6PSM!dEgeY;*n4_=H{0&xiyI#C~9Y!gOeU(oFi9 z9C2UnXL2KxBQMMC4x{7HjdvAznN1yblRbR6p~G~ro8+3SVs@~b?7_wXPAw7glw9vb zx65JX=jkX-w9DvV9Z2jiY`|L^hX<_ZMS<*jC%o!lM(+*gNn8SKduwZp9b`e1-CI~{ zE-ub5Ei5iI*a4?pD(rr9xw-P=Uo%U~x9_~h+q$$q%G=w-i6YTy#40i|x~R^$#e}Q% zm93?!rDU*0G9Eebd+JUucWY`%N(93{8+aj%Ol2P&OT`+!>~gzaY{*(M?u;^&FRrHY znv3FS5DDLt8F;SZmA@NDkJWGRiYnjy5Wa~~%XP=_V%5+JT-5lBdV;{Z9i4ii2k7S)JtI$ew&=hFv_ySa9 zSud8H5uuev206C8j0G{wj3|{S0zI1u&a;a2&9?p z;L?U*O&Ywq3MR0h$p`eEa*9?+R~{~K<)hD?5PxvvR{$^JGN0w$I}26CH}EpA60uD$ z^Cn^D@+=fZ;3Y835h;qTd7jcu69HX8hdeoRZ8{3Nu>jMouO>f5nrRo?BF` zh$3Q63!*Ijnvbe9?}YbNY5b)OAV<+I_bWytD=AxF=-~@*LG#cl&ucw$#Vgo%=@m?y z=!zN$d~E5dL#RQ-pDrSjqG3i)+>G^TV~t4``ha`rf*E+ z?xctvNg8)kuaEnsgBK|ocd|1t<*V!>9*{N(8bYbVvVl|dqTp7Xf^QI=3k6AJY!C&+ z404unIPdCszaQ>CW*_p1r(QWtDLdsUl;muQc~XH%2FIb0y*#P%wL{{Y<&gODUJJA< zr0mhAFpo}qY3w7h>p(Wx!Qtkk$A=9T#@z;!JsyT_E`2ZIH*SbNrRoXeZdXKI^QY{E z{M`OAI8M^o=ThFdf#WcQ0g*}d*2pjSf#j*>Iqj7p2SLo%7{z$a4d;1us;lZpt6EK& z7H^$%e~@v6#8EMGbV|8~wtJVXUYA)A53+{L0-mOG4UL>KUNvw;2Yuvu>-f1&Ni;ia zQ3Kn^qtg?9(ZK(odLcru^60cFG7gKCzN|Zj_b3|7%{4YVBiCjmn`JYsUIda`(K;FO zW+a=DNPAaTAR6XJeODqE;UI`}gq^lTLe*M-r6JINrrFWa(JI@F5q4-+4rmr;*>M>A zCz73cBGd7RC>y(!XK@-p$1Sr!L<#~AMTeTH&gqyd^v-4^dl&y9{4vdC>@fw131C-B zb1zPKWEY7gxhb>=i4Q=y{^6f#hD#8)_qM95@)YaN?RrO+%n473cqF=_HpbKH#t?OQB(_w2hH@7}`{9(gFP^$zy zSd!)ND_d^u??2ivw?v_rEQO`^3aQr(hI7b?7(-V_dltE8bv{fOQ_Bn+${(Z>(P;Jd zEN#V&I6)>;xQg7$VznJFnnV+`%jgd;?ZP+VNzG4cPw9(*DqI84$A)?)lW1)|C2Mn2 zT}aAX8u=#YYlCuuIlGTq^YaXONL7AMO~Fu(=)=^i=tB_zUZf*>K!r*0RULvpYW)Lg zXU(c*y;fSO#R@!4%N0g1WoMf*oq`ixD$JdA&S?IB!WTN!9JJPD;+^GZ4@*SQ5utm` z*yCmPR=`hhMT0P$9hwEUX75d!V-z|y+1iM9J-pc%rHgIjr`*eUTmPu;!Ti_i>(RMN z=d`1a*>VRMT={l%G?5}x?@G{7hzPGtae9I~z>^n|-%H~t9!Rr~3CTSV@!Rnbn(tM; zuvSU2X;v9*2L=(FC)H;!9)x(iVfMXYmt)bYD%k@dF>Hss(R7X$-lg=11^}SH9H1%R(dq4rr%@Bx8 zoJp_G)%f%}KJ$=oT8)$96EzE{EAB5J8ZF`>yw60|VjtXVAAV}p9@?~gNPhJAx)`J`4{dsvOU>P9YsIfEeqQM3@16UOI1_{|p^tgAbqJd4T^>&MFy7VH21e?XoJB>wP0&C%$ zkaEBk4Zsf*e-9yBt>FB0(!Z>+*>@HdJ744i^55AkyQ%*q($aqv_9m4y!2FQ?kj)rw zbxtz&KAX{VG$+~8`}7Bd4awe9zldl~vUk`s_AW!JLH3<*vqfs9kGnar%+DYl{Ls$n ztl2|s)oiDnGoIBA@uMrES%6MeweP8>5{2?E)X?=$JWY!~iAetHwQt zrhl;cgIOaf(Uh~<*?fRh|MFC%>S~14fgdP2ha|cJhD3x0r5B^)1dDCBXGJywWlobz z0CY~SVYtr}cS$@wiMoc-)FQY^OHY$1I`nH3GM_89Ds#X60VO}8@HY)sQ|fGNLdjt@ z#N7PDam0GD%-D=v#R#gCc}!jGibGS( zfj;2W3C06;J}dLuHl1qfG@~(Bu`U{zVqFYm9lw`uQ&`{vk`jMW2-eUcO*agp6 zz3*Kdb5%w0Jva$v2Ad&D4=keYoFWAXO302{C^g^1Y+_TI?v#jN2S0N0s0e|0N2DI; zKcWLBDnE`35;BTz)%TLRh_XgJ$eLh#lKNazCZWjcvuw7pIG5v47K2fy*>*RIQ{G^G zm`0s>7j)U;g~mM3fnt5UQ_zcg#`*)lXJ^epgwWTr0nLsxpC$G>UzBkDFmPX>GJj&+rr`Gx!*t)MKJK)@`Aj-ejPJ~kYpwKW!FWE;C?WWyFhX{+Y zf4H^TVEd1Ecei&xY_JF0yW0mJZEX^aiHpY)bXpUKc!%Q)45f+x+{DOO5OYaU8N86D z3QQiWbIss}7iu5Vm67kP8mre?BH26<_R=kR_&?01$z$>gzv?GF#P_IDbzJIvXr4?erL zkj_a&Y;l1}?#EFe)hxmkhev@1)7pOc(CKEx9r0!CN0ia>0*PsZDBlRs$9O5-BcL(v zkWif9%omyqrzsr0%Xj0fCnD16lQd3tqyPmeFc+8!in(>^4>>qSHMYiT->Iwphdo@{ zfW0}|L+<9#45Q{1Yqc8(k3Rst*J@w~3Fw@xv3GA+?vVPKpJ($1_;+*@Y~EYPBD#f? zt)=?o>q2jTPV0azv1N9ft*|@nF1yF>vjuk9Z|}mqLlGn7JYfsXCH1H1uqW&fE`2Ed z0d3KRS@!f@&^%`eCO)y}Xb=il$;pWnesuKWGK zFs?bPghPg{X_nfO8yyUZFju@kP_8V%=v{=%NdGgxsmz6R<5{{%1^_=hH8n-5T^mf} z{nqhw^%)z_e*WW~8(&ktu%SBi?Js|~^~cYTehzSm0kPkYTYsb*C??+i@JFq`t9yXb z!+w6N^*-M7w~Bc6ev~8A`w_XuY6N;ea(XpCsjf^T!0-KN@cai~Kb)F6ddnCAnCNP< z8H#9d-b_T)O&=&zfDg$O;3F~x_&c-LrU2LOvTu^R?8}=1C_N;ya$6^LV-WDF0vI;f zK37j`FfZWDi7ZmynXXbn8yY;smR(PhQ21n_>$D~_2B<3wb_`h*pII}7SXM{!AgFsH z>ekEfHG|qVS#N7}W~{EF@=LnH`tcwtrIMykW#iQYo=Jv73ZhJ$(Cn~HJh=2l#9?d7 z9Ur2tjgKC+_qV?PcJ#qz8&CW$t9ab^;w{sd0mJ*U9wZqsmq(J1Ze^`)@Qho$jy8$!E(tiELIP> zcgmr~&UgxY4=qMmFXR%z<-ms^gEw+LFOR>Ed3nJBn51$A{Po8%=xN@1#rsTNpV z9)!H;AIG8aSw!iw%ZL{otjGCSmQ1NoCQTRV$nbD&FM)bZe;hOD#18rZD~H5%!Ii)+(JJYGk{GyfIT#k z^cY5sl;fB3*TuUv^W4%o5CXk6PHJ9}kPz%UvXud+$~Ykz4j z=uH&P$iC<+52qeK_vlZ1r{$_js(c{A{T>~l*Fb}0ohx>sU z4nl1_QmO?)CLy%w3bo@wrvtZT1;diA1gwgZW7&*XdvXz~?c)o)-xQZU{qh0*Fou|^ zC8nxMI_eZ_745;3W$HACgTK-tmIzQmO{pyx!V7j0Gf$oUh#NpI-<}U+Y~nDGH~yofe&L9liCZb4zO!#F)#1co$du);0@Irq8NObB( z0iHV&#Z+V-8MX-+Se4Ek&sVY~W*t3}J>Yy6&y!uCK@1kN+@tqHdXlSHBN5N&9WIRv zeGk#&OS}tDd3p@@$^sen$1(GJYDxI92B7TrzDm?PVO$PtMW4o?-LYstpvEMXe}$Y! zz`cO@*#f!E*D;8nS;W=pf5ALjresboA|og_OvD7@3rfqDpM!-=dDlw=vfm@Q=uExe zo70!xs3;XQ2?lX$voDv~ibe@0s#II@Fa{c z;NtvMF4dwhsa03j>FCQ%Lq=7DW@&OQqv)AjQ_Jp?D{7_1p91eRvcf&W!ft4uk0y}Q*6jFnx1db{~&>WQk{;* z(6^kRMGg|44r5T+G^c}oA%^`7(nC-R4d=`yn;jUS=daZ$RJWZDqPB?I2qV`ermXG| zEr{FdC@y2F(-r64X+z?g7p-;W??fzqP*kX_0g&#s_81>B~~V&WS06kBB;PUEO)O@eG978957U0R6W^3{$AJ zMEKrf82smRr_pp8(TQx#I#%6zY~dMe2Rot@8IXrOKqYFS{1v5Qd|t zS>!f^Je;=(DcsbX&P zS+|5WYnS%Cdh9E0!2%o@#go--J`mj~hg|?kuWMr=_J<&IhBOvzI0V)<8v)il@LXoy%ty}57iP!2n2bdZM*qdNZJUii4hsCS zAiqBZlA4SFr_|+R0e&_FP&XO@(p6kviiG>4Na$*9F9k`t39C|?4Cp#Zr#W`4#(yE- zf{N`_Ek_L4>Kn&`J{Tfn-fje7XavW?GDGi|Wo0 zRMln#Kv#8ksi}WFY7rUj(WRiAj)J08IhTUb83n`e-Qx*$Hbkhr-3Vf7HhnzYPln*y zW;s~*LUI-rarcG$*6>GbtmI2>Z$E8It}EuuHaV@BL}en5sGkPwA`@E9$xXAvN1KmU z*~f5k@iPAHGF6T)AZnwqlGffG0ATRY$UnhGyue{BxMF8X_|zpwI+<#jAe zYb_T4QR^R<0R^#Qcx;`2-1;XfEn5z#NNAZ-#z^FU2=ec=9Zsw_4tesi!e(%^U~Cd z$UH&8*xB0O_-K9iaQ%brhueprLR-%i)@&4YU zgRLeb$EmEx6^JpxwD7Rjk10AlyoO}cO#7$sJ9k_vblUlVc?@w>px4G@%V^N5YcGtW zu5$OF@CG_;Sd+2s4qT-moOAYGFUykETer^6&YIn5(2UdWtx(0VlDFO`oLZKPHXTlSaWU$)A=}*>)w24`LV`KMxj`@CsApKoU;C(I!A)=zEaUTJd zcq*WKmNpuL%;J=u&|z9a(Hr6vLDOJ2rTsxc{=6xLr4T{$#&q5n1>VgeHN&_|K@+qK zyBr)_&=lzz>81bxYWYqahVdChR`|su(i=bLSfln)-0ho&Q$SQ^>A;6aKC4F}5GD?( z$vqbEC=X)wb}LK5D&Ci8786_EtNP9?Fao%X+w_1_LoHXCm}Ztkp}{iJ=}DL z)n>zf+)tp34tVHYwEJ$Jb`>ry^Rj}Sv1!ofUSzt9cp`@GC@2T?C56Wm{MlA_mhzVq z608u?*3|L;Jj&WwxSA8PJXHP*G+}8bVdGe@`F?c1dTVB5u{MX(?)NQ|gyO=hXoa>f z(5%^PLK8yHel(CaNLt28eHjMLDT0_dR@Gdbzn<3f zi>apBk*c2cLxs@{v`T^SGp%`(92S5zrVX}X975s64BQ5*K~5xEk&#NSlfoHK527Ms zotzoLyG>|!p7#t#^UDPoWY-VIvzqSi=AIxv=*1{t}IlbwY;+6pq0gJr5dT_`x+^+ zwsi0I?JMB6@o4vOYxj^n*nhM$0=YZ)?%Z3dK<@UP+sk$n(2A?X?$*qM&6$OjnZ>P{ zdn+^d9(;UuYi42L*3A8_ndQxyg~gf8`!mZM(aimonWYa-e{beqjz<13OG}M!`|y$T zqf5#=_wL@U!gle_;(d#47FSR2tHE_~`R>Zf{X2IT?lqT|mX;T8YvSEqxn~#L@}2w6 z%<}U@;PxI~a4tr7WTE zn`i4h<7woDw5wIH3lZl&lGBEew^x>$_wTISzq44FcF#w6JRZ=lri<7Q1?-7Mu(rbL zWFfG&aDIDXVQ~q(`0eJsmFD98#pdDyqj-<^@7!O>&mqxK8@?l;ogM|eHpkv)^Naam zfr3-1O&Lh*I6I!KJe_O8{@n92Lz$Y%dZPCE#j-+xvgURWWCQns{LAfI%%YO>6mfec9x#O2ba3}eZ?8*G(*gK3;+Q$e9peh=HF+x7nj!W z-kx8$cl-AI!otG6`IUwB_4x;Pw$?Xq+gT!faYg4AL1nUCie$qyC=EFDB&=O%lI9ol zNkq|$0#$UFk=lH1jud<=MY5q7luL@Fw3@_wqB|0($!lZL`d(U{CP<#O^TLju{6d|fTKX*T$W}Y1M zDJC`2n&}|Bg(?ZBIKDNCzY7Z`&32(o+|FpM4lK4tV4Xc}mkX(V^dn(`Np9pjwNco0 z4GmZ?@6v9V~NnL)VF57(Y<1KgF!zbZXH~DPe5F}un6hDHRBGZ z(}*9^bMFX zn4N1d>^OXR&J5$D=7a&P)QGJagaEQW)IYU}WfL)rPPy*F#i|5Pp+{Ng5Z=;{+K`~@ z-PB8Z4M?C3CK9M-F;k%@>}DDMYv+v8X=$Rf;w! z6>w9qV~$wZwBXg6A1~9Hf>9vkX5L@<5L{bx4g$It$nl^k<)NrOxaMxc;t@u4Zi3`b zA`v`&0>KgM1e-gpfpZ{rxYNshS(+60ux7)4S+>_P$#i#lGV**2=h)xlh=35LP zy$g%0s`TR%^Ea@;nnJ{6YYk)R3hG6~8|xka1Yh#YS*=ws2--a8a;U`AaUKcR`o{F7 z5i9m>Zwt%GmG1|FYEeSbXxWQF-4eKDaXr9F%sssbNkr|I?Ledrg>*wJL`cbl-%JE2 zeJMaGvK|ByN&+(grUyV5FeL=VF2y>a^CeE=Fz#MxqNr_Q0-X^0(`*Ns>58gm!VZcP z9!cmG!6en?5lR|y#8&6M2u1=vYaOPsdM5LPl!$PckkzlB5;+#W9BvOa? zMgbU+0E$RTT)kNcBEhnWgnljTzz>1cOO}!fqiMDqpRqG9L_oka9(0jcjgu^>G{;R9 z(Ft7!B1I_S1`Dt(WrNYpM|#~@HUYy+b4Wp7Sr7*ySG$b)nXirZFd zXT`FKK{t;*Nm{wOhEkBWH^3cdv2}8$IqtBC!-?HX)nY*r9pY%Q0mm!?6uqybj4BgS z7PHchEiEz>Oc%`#dQsCDMmD=Gs<6yIvn?#8nVTH4bf+>g?%!ZnZV! zZj6(0Q~T}^a*~~4XHhGRNxc+Nd`gNMYffN`&M0F?s(`zjX3d_^IS!6yzUj^yjn5tt z`lK&P2vkMg5#Xx~HzU<#JBPoH%|<5(9il2UCC(PTJHU>diU4V*%`vapd@yb!kKz(f zC_3e7(Kd(uIm(6=d?A!=<1Y(k(}6`<^K3(s4o!qZ?+x{=L-(!b990|^6>!z- zcHw>mcRNFVwRnZ^h3epPA1(BqY|b&dPUzi1#1Y;$X^GK)?CZqzG+UP>K|_}oBKOlE z)$+CaC)5)TFK#9PDkrsMwUR}vblS?*Z;dS!e>Ga5QNI_PnITkvRRgn6D%8<5+fWa4 z1&Vmb^e}(!_mDv{Ff^8k_h~2!XgGN^m{3F~(BOF&1S!9#>Gm1PVNA1!v8Tcm(($XG z38A>ayD+X~Y^YgjnE>h!#T;v+4=P*L@M3Fhj3BKDLXhLs3{!F7A~GPFC;XzoBB200 zTQgOPENc$cKpxAyE|So^RK=|tEb^nxl$R7XOwq626pz#D0LeYCl%m|`9|N6wgXlyD zE>e?TE-u&&CE+WmaDTv{D1b{tb)rLi-dbB&0Cc=LjDkx1F|ol}j3C3bSQPfA8y)ec zIHYQLB{|9AM1V^bCt`}(bhIJXCd+CItMf}woz-T_G-L<^O>M6%cFrNYnoTL8To&zU zyALlG6c=S#T(9~0V7hV3n1;C~oHzvM-L_oD0?|Jb3@v94VKU7&LfA}naMmbYH62Y@ zNW%Aq>R0X$(^5&}Pe*8AOi_B`lJHCvE|Sls!j)<7Hhw}qmZj~Xq1i=48Xt264OIh^ z2GM*?-%i!2ji*z^bH<1vqD-4=8*f26`DOg1s^44p->|M?LL7(Cfuq@8JkT#9s zpYZTCgiv`!6f~EHH!0~PO|cuy)YELq%{8_-)KRr&(t^pmOO3%jtE+ zhPhCaUpKhe^EI7jnOfI+>+02EQOEBp7oPp3qc<8M-{{iw;hLq^wj?QoFvA#G!FGmq z;qHHpADMYri7Iw;d!lHaRvA<50~bK?I?UpVtD_8}^dM(S<&f>@>}X8E_=``BC{Spt zOs|%(gRl%m~?xPgFl zzLy3}dU@?yRB$-RJpt z(;a=*FK8q5cJx+ORNuBu6ds!VAesfkpim%!ddcwq}uljRbugCXAg@Q%Xv0 z`#53M-0Ea6+Z$s$Ul-a0uk62H}f7trd=SROeH8nMYsC3kr+B-k|+Rnf8wdY5_KDxfG`ZHhK`Qg`| zAN|tQ)Ko!VZz{C@eCKDr_WbC^)YMdN{$qc<(|Rv&YgfPh`A=Ja{`}~dO9KP@ZfpGQ z)<0Ch^H)dv+k36Q{`~0Ikdvdr`pee(o2|dCYE@aW*;;?S^*7-N`e-z%d-o>Nw|8$G zNqhH(so1+$qMTF7lB;*Gl1931PMF@kk<`#XRgs`~&-k0(9Znq*$>pXGT_Tsw)Qf_+ z--hMDQqb>ezC;7Putcl8c7HLK1dvU{++Pe;KgbP^Pr z)T`j=hv_`INFm<*1M9tC7>alzUK7`sqMO zUXE^A2n2gTInj%ZLclxTAOzc2TliveVc`q^y-QkvqyftJJW47oRpAW}Rnn_tkt z4h*Fj^>d#~o=g;^xcH_U7V(Db0ll{Cbf}uMd4e$ue~V zf!O#L)(1~`_`oAKZ{EUiFi5ih>Rq&4F!lNaY(aq;3*E0YzD>{L@k0g^50 zaPCN(DQFQ7ppC{!pjJ8LGqck5+Kz&J&6mIz4vH;`ujOT<$(+yq$c6mGsibz}(;w%# z0n(KTpC15)V|SBc6o|M?quM&ox*+beQ!f?BGhk^B-w-7co3@Ea^u>P=poYnA_g%c&-u~d7L3UHVd8M!YBsFqDQ$iJ{Agxk^EL^6 zZQJbg*0bkFixZpKHGr)qjt3dfdw#q1nbH}KL)?ie_g3o}bYzD|Q&Xf08`rG&hf*h` zeSf@GDU7?8gM-Q|@wyZ$r5(mnYUR>nrCj=$luMtGa_K+#g=^)~b=KN9DQm5xlKBZ% zE;&0G8<-Bwl8$LF-{cQtDJQ6!9>!fG6;(Af3a6^ys`XA20KQV~6F*0ulyc6dE&a8M zwXrQUOGD|JKqkDFnX^%GhNb2OQFDSgzx*1DGll|XHqkn88F|0RFYX)vF0)!nixMAq^l76b=I5MVH>K9q&ShKz@1xaV`-M?LzK3_ z6-_-nSQ`gC(;uq`AIvpbUFVYn;UA;|@isEH*jEuDSDK3}?8A>ff0;?ReW!Wn?%lhu z@tU`^0i`V${32XEGC(Ss;EFu-gk$lAIO#C%&YQ`ech0YQ409wyeMAiPvSMu~pf#GU z{$6Y2`O(cw0x2`s8?6V=={a=w;0hR2ve@5!epI^@76nH80T}I1!DwHuan5f4hGDmJ zCPO0C<{;#0`g@9zenO1&?-L{aOTYMv8R_NgIKS6%e!t9D+G(~v$a-dF=ZG zo^lcPJfFSi;Y;%~`{jEgN`=?#r0?56t0LoRA*yPRd&y@vZjcIv9eVNvFQ^0U8HUgm zTj$&#&|82?#-mv?R3#;faai8n`oub@Za&)GV#bkUYk&XIK3ii;ZZGxt_y^q29IxGV z0tqjzl*0}b&bo-;nX1^KNXUwCzCZ@{>ldVkAq=)`cwl(;rSMoyncemlN%}{{ytEb`Pd0U++lX)m)hx1HAD4HBzt z-Ns8+{vxOG2?a?|_V)<%p~yj`7}Z-2&IDi1d&K-&G-VphyY+)ED3IX=8}Hc}37FsZMi1?n+#;H;r<;b4SF|*ZzBb^lqyCwa;WnT!jLO$=M}a@ zU+Z>0w6>jPtdctw=s3jGF)Tz4N)eX~J{iD1Rh=>Tz zq?#cl6Hyx8?YKYeVpiEh)XHh7&hn~yUeI$sAv%;CCJW9vZZZ%x`G_=UCIs)5v<_%W z@=@7?Iap=elv!;;sgS-y-_0 zxicIm?gZx}Hw9}{g^Y4&RqWXms-P#oKt;E>E5`k$ighvG-m}qz z>^-A-EHvspGX}rNsYAj0a~r|9-)WwS&^yk^4m)itiSZ9eV)RI2{ML7`CC2NgmpAF@ zC6^c<4t(LU4+s3T%j3_57qRz3d}?;{PwhAmpMNf5S9T<49NH>Y&}mwAk9ps)CZ-K# zh1p<-7YTQBYUGX0jx%kI_3qWoe3^rofhcJYlMl4EJASnDU>BkC@VQue5>e)7`BT^bqu1%^Zai5u7aJGK8hEB7r|`rhKIFIYvVEKxoKC-`WY9#e{g z+T=(zZRl1BaP?5I?=2G^d)JAE)ob&8Lt>m$JOW1DH5x41xU)uHMHRDXG1gkpl!k3EL9^gxJ1v0 zXm{paR7{ut<*}Z!4^_phFZrR>p#c{chyI9xeiX}$XrXn6rheb^dm@^=^oKe`p!s5N z6nehFY6!M&x=DH$l4AM2a6f^NCvDM3{-VP6%D>Y*CfrAqDGvsszUT;_8Zy-ocK#kk zCfCf5luOjr$HL`mI=lN44a^3bTvab8 zTJe{zJ-H&5)Z|+EQqafckoK*?xIdKORO#UgxAKr4&Nj>S5=xxreti4`wq_WFX39Ht z?&r9wTAH(|QnQj&)6Qa;nw`>3TwP5~g7P4sWCeCbsxI_Ctoq3;O#_%(5^dy(Nb-)$ zY7n!eNTV2bROC`~(d0wau{TWZqTH_~`9j!VN^@_1$q^>BhSiXYc4gdLtq@FYc$!_{ z0um9qun2RT;Bs2u+h&NrOo6jyN9bfkx%T%#oT`Z5sI81vNz)8J3uNNZKsi*?xU=$> zE*gdoq~K9l7inQAG=ZKds4DwlyqqkP#1bwwiG6H}zK8Kiiz0d$NjnhtxtBR8p3kq^dMn z$&R<&OhPZ>*?j07H~9eA++Mjg+^uusl*jL|6UAPSz03!$D#NhB1ts561u+3jwCyFr z4yr+zW5}h{BPi~mR7KfW|L-8Hj)JDz==HgVLaI^Z;+u+ZFJfOnSTBysbwRjb)pR@& z>Kd+s*#4f6TFWDJ+~}{)(WEz>yAlmNYQ4!gU~~4ssKUv@WN?vcC^*`oM;RRC!E0y*dmTT zM)d?0OVMSgncw5&QKX~UQ?Ei&K#k+j^H1=)0_2c41LE8$T&6J{G2W!uex9BWrEn}c zFzHeSf{x zBO|gSBCEPa8noDkTI>ZD{6c7Ok)?kCyUSqSCjbT}1o5f~r z{Mhe5=RPAMv#Rw?09g2p@WzlS)d80+W)X$1%gxxJ)^=OLK)Q>Qo$gG| z?hGA9V&36KNfRg87-Oq?JQujO5FbIvkDxN!c&N6TO z7K5-g?qEKZAn@p?yUNyi`?VB}%1Gz;wM0`V&VUn6Q7kWYI((F|Rn=K|g+qji_kG}; z$mM{@XeQ4DL#UiUq6pDTS10v?#kccV%1QHmA2_#+z|PSa&|rsWDUh*ro4rZNGa1s6 z+!K7_>51H1CNBU9VKg{s=qCR17Xg5CV02w9#JQImB7tu1EE5J6;zhG{RUHCw6nn=# z5ewd2ZU@_GRwDE$m`Wi|i|4(i&=(7ynqy0ym$u+}X9GCc5*Z_GOC)oXa4n*aor2&w zwSnL4{AWVKM=KT^PYELY4t$oJy=BsihSL8x$$1pfEz-2(z&lUeoYB5HA z`l?E0q9_DxLzsw=&Yn;t0S69s|7{#!G z`J0c*&g3sqhoDA#XQHdYcAL{dm9B(CP)mPyXRV<(f1PSQJ}1bDfZ4Fh*}VBZ=|+}X z90HY%%U3UVHZNZ)UCSlik~6;9c6Gao4U^+ot841Oro=%zKLQQuu?*3bL)ucNUM1ni z)zvVgsw{f+pcQTxceJWwMyO|54T$Iovu$e6l$vO#XI;ZuCa_zeBzk6r?YfO`mKT}sWtdFbVPTnRwnjNXg^(R4G{abg?usMGWSs;Hl3jK0~Eui=MwpdFLPcPUe$Fm`9-)KO{ zFivho{bIK*2YB+u9_trZCC*vQb@9j-$uwuZD$ZXxXC*bmFZx0^3vaGaW<;}_%3T)rrLR6x;!;{^*IT^z~r!ntb8 zT28c{EA!@v39fhR=3@4xmSwAqrxn1oInI4yIPF7m75NC2lBT63j6E60TC%7|F}3j| zeTYx)WO73LYPbEETkdT)i#g=20fDD((+QY+K?aReb5UGOvurw{)MR!wwXB6@AZAHz z-UY1DK>bL2QYH&5VH^r)q6zE0E8+#*wv>~Owo|#xAU_0a(B?vXl8az^pCO)(M~?{L z(>yy%$)3+0Qb=I$*yxc9%p)Vwx0D3>-5sW@sXquRZ7evepp<#Q$PU=Tid_{KF8J+t_9{In&V-DbN~7)Ud1I-XeKcTl1k{`(r@PNo zB#J;908LObds}n{#WaZHeJ!Oa9@tEEn97{ArU8_iSHNo`i)>^oQGd754Wd+R9SZ>SbmX!`M&9#Jh_(Q8q)lsW zO5s^V=MMNe5pJ>=7jTNW;>jofnS^BNWWr%hR8gj2g?-Spu ztgV>?P%Hmh?FtDiYM!fh1V{B&^Tvnq{42=J@{){YAvu*eKRS@ST8r+ckHe zAC9ESaCe92*$?8_eKR$ExnMW;A9J9sbwS3U#c+@QdNmHsxJ=FWS_2cs+M%tfSmo?g zEy7ExMwHT5qGKhtO$@18GHdOQb2ujSy1|O zGruZ8pvGcmh%9^d5D}8PpJZ}3N~bx;Uz`m$vewbm!BH}4>ZPrDG_3I~jY+m>mLSjg zi)ziz?1l}1l?|KORJ8!K>Q(;FaV$I-2cc_24~u;MU2J1v+BI|G%`$VIao$-ObTx7Vv6_RbfoV>N-hi2UL#j!FZ=LBCe>Gd?oIF?GXNH9m z61N5S=WjW!mX@EWfGsl3n4Y%lJ_pnZ;3}@J++1EAnWiR#_=hfvwL0omf1LgoLW_iR` zaySssGi{S+&uqc@vLG3I)&=N0C!dK#ieM**X4pu&JD}cK>flcsKsO4m#faU+6&15v zP`ye9!63A5Fl*QO4#8rXKXq>tT;^t@-L5Lm>=B&Sj3m2*z`%L2y^jtEXPh0sKai6W zk}QcUK@@8>bVkptMG6TV7TQv*T{p8paW7U)4%Khb!~%xipR_?oQa(B>914Ndqqg|3&mS)XyzGIh1>Dt5w6boZXj`A%GRhkw0 zV%r=raSooYf?II*PtB5E&QG!WftqMTNxS|a%In4jeCU6GDzjeX>^Z3py_t^n;~CDm zF(x9In4=aYI~F#x=2D(V(U(a&-3j@wpjlMMzm^t)tEm(D=w`rVZpOI4NYG35He!&{ z5eW%5wWNBCOTU*S()x=>5V% z-9+pqE{D2y_w(J~tzDzNEpfVa_1=#x^ggq2u(dR6M*bl%&3m;KBjLh4AN6J|d>YuPpR_U1bvVTi}i)J9b^Q`@7vgsNGbaJ3Zj&y1n--^x7)x zpx3PvmE%1$Fv25xHJpf$M#M4@?4ItvQj07+2V9c4BF!|~3%!*Ejv?X?qLlom;>tqr zJL1~tgg{ovc1l<6 z{(AQ}4z}J?g<~xbr(5+tv(Wp=TF@x|$5i~uh2GCD98g?Je+k1>8$ao~-QVbbzV?h& z)S0?P?>iQH_v+7OMP4**esH1pBMXSsG9W^YC@B8S%Ge%u=F{h}L-FwaPJE&qb|^KZ zU&ZW2*qIBTuyY7i4m%V_#_yd`sdnxTs)Zej9^*Gv=pA+_dW`oi>`<}-@3&dl72cW6v1`6c$F8CH6u7IiA;+qb6su-Lv1-=d@-$Y>(^xfc&R8|ai*C9kuB>hK zF0YhAJ3>Zq115@-OJXyGF9WoV+bWQwQ{!7z*p!#1(eNb>6p@w!PLhA``2wslax6Ne(QD=K zM+Db#a6cMP$AX&DyD@i#=cGYAWoP41icNX%M*gx4h6wv`{({)vFXSOfI1dN+h4($d zNbEti4D!4PvI4q%AKaVxxh^*~e)F^axRjHwV(PL)R*pj#PCx0nrwz=iz)UA~uuLZp z49ax!#~YFiurE%E9{={86EutHtC5C6ycn$t%56CvPRB2s~4xG#Lj;up_f9VF4*60cpbdbKdq;KzgcS`jenxA|t6%3}kJm zq-78<{;qAHtL3DBNb=_pA5OPXa?8Bxi7bW^zKx|e*JN>texE7mAgb0Y(I{dW0)FLD zny4VlTI{LFI>B}h`c|y0kkm7)y_SEJQR=?cb0N|&R8fvIu z%AL%CC}`F!Fkt}}RQh({A&d@&g@9IL+<`LJxPdD0>%5xY?Q<$7SQX^`Y@EZudoPHJGT^f@!^w?x zmW^{t2;yw1V|T)%W@9%SpLQ?c%unSpc!pYK$$y#6f=M@FdV31Bs&bX5p$+(abt!$z zqwzE*oNq^zJgMpQf?&+Ds5=>pDhwaSvTH)2UiCsGXGC$jT!xnP9&r#YzP#rhz_tr= z{XExgA&msyBNbtog*$Y9Osj9~e)GZBHy_^0;YYr{`~HKivxhe^>s1?P#ypP>6q7P{ zoeUwnO_$ZyjSo;VrEx2H;AX;y6mC_gVLqrPD%YIWs>6F+Wpc ze!l6QkC^#+nmq8ScKESshixi|<2|q0oA(hZl{HJGIU1L9YWab1+-wZGS+35ftIbe) z;Hx;ejw;ugJH3@d;`een6iK>g(j%t1POG4@F4QJfpfN~;Othg{9<#zy5j9y^u}w7d zL`moz?=N~>(XM8i%RX5fJByg+a_xF)3X3;$HqczV4!1zk@+*&Atx|^hl^CXD zIM2Wgt1Wys5M7L>Fx0*9wk{+|vYRwf7Z~^J9vY|e23#uC-wsH0Vd+*Dyj+RR*Pl?TeoQDz z8A0AH9EMjJI_iPS1ABd<(6B}mL4iRyq*A5kEWHGEQ#ZrIHk-R}^XAN~%Z#bo-Y6j% z`g8oM%7ovYUiq6r18;DLcbzc)9@8IbdX6x+U5^${Ov+PWKaRE?%xbOu2=rxz!!j*VNXD zrsn1D8tatGeb!x3rqx<^oz2n9t;!%WEj|HP4*2qvTNr9>s;+mp>ZepE{g_swd--7N z9n}FGwbnOwKLzd59>IO?T*7C`p`|?6^6J88$vVAUO>al|Ea|YypX(qSK3g~U@L8>f zTCS?0INb@doxpUlm?lLq84cqoxtrZ*h15PNq+TP1)Zcq*uK4sd?&)is(gf+Gq7+WK z<*Aq)rBGR=R6b|AH$LFgnuX!)LPwS0FgQSS{9~E_ynp$3D(?L&hUz3M~-w@JZ0(~1SvXibgmk) zcBZ!Wj)v~2M?iOErMo(gyjHuWIZ_+l<5eziG&FB~WfsqsKl)BRpHH`XOuOya@FaiE zX`{DXy}*>Ar3*i6%zr_2+JaxQ?}xe*6#oekTZh0Es(Xr3alZ7fh@#l}c{?S>)12HK z%p)20U)~RpK!w8gIP>$hO(;IQZ&^lNW-h__` za*_J^6)JtPjCwg41e097^!4Bv--0Xs{p*p#=lYY1##1e*xpQ+~488hwcw+$XWg9k_ z4kvl94?K$#vP9!4;ey!|dpyu+HlFC^lS{A3^mNV!5;5bs&+YE|W*w{|;D`;58o)bH zMKC%1AX$JE!9<@S1CJYlpQ>T*>2X{6@Gwh6`63=1cZQGk9pd|D_KBSsV-H6?A0`4ag&?n*`Pm+ zvQn5x6hz4409h(pDH$Go!ibs{IUR98*}%??nl`Xytb+%e!aVU zhvmB3ibgDAj5KoHN6`vl66#wyce82oZ1;nZ^FC?hy!xg^FbTKG$G7%-xJ}Yq?YGio z!|kKZFx=Mi+>2Ft&UHZJ%<$M^P9=0<*dM3cQ5+Tf{c$>!arQckc;87P-ls^!`}9{l zVw;1f9%=eDX-e;Ft&^0^YOXbgtdF^+B5yYFBc$%4j@^ zk<)Q6$g&_Q_C-44K6;loF23BkcBAu=wX174Zh^78vUcOz<;_iTWqm_*#P!a`jkSw6 zuXZ-X^_v^l*EcV>h1itzQpjDrbnT{KKh&~e0KEf_Q#}32B8cL=eR7H0+)Ae+XD8P% z*p(ua14)@60x?J@m>z|SncX#a6T~S3&Ty1aiu<4LWWl&C5P>*J$pTx77oC)`JIS=2 zW;53#n zI$i4yjY+3IxpZ*#FiL>vsZ$NsG@k91wh<)5bbQH@1FxO7N%VeH{F;^9$YOJTM-ORw zU@k%Osv_?)un^9x?nm$(Rlc6d>*vByPy>qKnaQAZg?o>thq$AiIe+flC-MLKA5XAL z4+F_z4G47kL`u9CIgs1LPbHu%b_8D(VmHVlN_1PK5a(!LTM^ltDeA+$A2Uuj8jPJ_0~r zOeuGGQG&Go`AG*e0iputG>^#o#D}!{wG8YVp%jB@mLUqeX{qieO-%)n)3SJQ96E7s z<=o2SrwtAyW?5X&nb+%d>eKJLGEN5(Wjt`m!N=6E^B`whzDXe`J}Ium!A{=3mcD|J zzYb*PLQ=2$p?uNIT{cLkSuO`*knBLQLOewiNl&v}UZh_krvhUszN-ed-cH0gKAUEC zGj=IErr-{dsnw1Y=gt!saWb&nF{7LH97nx+ZSxT3VUDU*%iFA6a=qpF+BxIMCuj7z zJVWQQVmtGC_Gd{Pdx5RW=kp;B7;pxn?P=kJDuX8*$y@K(icGwe%Ea(?`eN;rUY`uqC6H1Fovzvu zO+P4T#d37hU}MMs*n$u+1MB|%!XTi3pt4(>XpZBz-1 z&`&pbQOjkXM`_Z(D~%~&_2Dp>R08WNt+~OYHg6uiE4HzK7H6sNC$KGILris#V{^(w zV{XptiQY#P$`>hjk-Z&3w|TzeuH1KmcNZ!4mn$GDx2}bt-Uj%<%t+?-QPvr4SH&k9 z@Nggl`G!~#jU?S`v_yk3zOkYbhOMXp8ZDZl9RsB?ieh*?q5bVUE&MIxq5U%$fXk=e z2bl~C*?8SDIC|zPz*sPe+A2E{gH|J9i)ZYxM&`wdHuQFbSgpn#|KUl!dR`0?vSdYX zNP|jwZlc7Vx6bu7|5@hH$4WJEAQDa9pM}aDKtDQZL=_fQj*|ti`q!${eF=@UE{U?F z5|CQRh=?7a0NnTs@GnQ>c5&Q~pz;dIaH?bE+Zj0DbnjU7 zib`&#=c6)HWHO(|lnfUG5bjs{=H>{XZ$7yovj@h(=N(x%rv>Ln1IfklXk?~tx<*m! z(YW6q2NU9L;a98s!E+e4wyFN>8~~JiwhzqQp?)+#nyEpU>T_k5NswQPyPloC1SOGs zTn`qp{4efoadmZ3V;*&BAC`5|v(qnVrZ0N|pm;zbINvrj<&Ic2-B_wY5Tyss}Pa;j}W`jh(WZCSl%+$$MdXXaEE=)VtulPMhF2l3-4bd z<&g53=My=IM*BqU6S?QiRAsT9#8YOkOtvW9e=dSJlfiIbUmY}6i+27=(HElH4C3-A z9gykHNl8?hhM|kPHo-t;M@5-tNuM&htd^-eZ6l_ro0hT}p(Sof&AZ#db-(zk_EfBj z%uG&y$G92?bZ>qyrb+GTnNHx9P`Vw}$*@gP>P`=G<{W;4=;kLz^Aq;s6)OgAufKlM z4mIycv8YhTd+MWPPmqE5F?T&0nWot1Ih&^r6s2w^2-SJOXx0{~KJc0xB8{}o^brh) z$hlIajKJ^@(i6w%re73tJwboouS2uPul5MF=_M(DUt6-K>-+@j!Xm|=D1T9i?J*MD8J~0 z&$!8Nz%oQ7`;2lNVYsMMYS1E!b|t=1Cw#=MR?R5X%!VR+c{Y?8TJv3_*?(k^oTPak zZO8bH#Hac*TZ_0=nT~R%uPBws{L8Dri#sl^M$6tvckWotm6?BLO~H?N@wkFaJx36! zOT~y9q=p!z@pPP&H6w0s`ks$&H^7uN?l^Qup`u&etbzUkdOu%u#qFvkMK>&k%S&A% z|6d3vDVs?#xPc;^!3>nx=qG67ST(9Pn0DPvObLR6AW@HMA}Vr`M@bRfkMg$Yn1jbv z0k=SrejeC##W)fShq)E*+YMkHW<&$E#X3?mtDz`ga-$HVl(RY~`*vQFASgAGDyBoO zW&bKy3ks)}{-ab$y&}; zK88?b%%snTisI~SOA&xo8cKxALrT#WjywLXxFvHUHQ}x&v@Z3~Y_or9I21=IcB5Qn ztCLD=(;_a;nK_C&>7<*&!c@RI`b63Q@0=6GQ^!>WZz5M{_f&qPq|LPV+IK|^<9Y=2$^$v}#U%+Qh3M=)z-W2BE20UUxst}iWibG1B}Ej#92MZhjX?kC&wJeI2b0Jl0@R>3G!o=-yyXny zyhZW?s~q$*ROu>T(&Q0t;QC3uJ&D_SItinotzQ*O_BFQEVj=UQJ>F-P0irdOsyZ)R zt71`^!k(f?HJI6QzViNaA2{d6z;LffrRdhrY%3P2@RMi;aZb-dd|#?}La`^eMV#(L ziA7e{rrUnITx#TM;j-d~#ZEX-JFr(CR&=%3?s9kHU+x z-PJ70f`3Ka%;JX{$nDD=%3v@`G%`?Tu2j9m`ox7_kYMRE4(>{Nnbdn@A8+mMp^!8~ zwm~>2es?IrBoeD!0cQn@speg|&z%^M>7od3Fo~)?+1?z&Q8T|8kIR*@P-x1d1EKO;v#}dm?yj(*l3Te}Rce}~-S0afXMeZJ zT#nl`{h98sat24YX+^1Ts;?k0`9D}%NyYT(-S7iKAWyf`*%}|y`}cJ}!~R2VJC6%6 zRX@}H8BX}*R8@DHW54zJ-a8jKjHy$tP6=!Jz0*xO!DqRFmcyYNGqqoVn-Ma+IZy=2h$_NQU=p9b!DQw8pDe4+jrdv!S{7zen{ zx$C+;n_(zGS@r?27=5m+^!RZ6a zax-^5P9G&>{#N%av)XgpI}F*ox))45e8#%^NtZnj&UP<=k^9HsHSliNYoM;V^%(fz zd>(`h@q(lwIy3cY5U_watKXFBHg^GNv)<6P(Q9Z$VU;V1Xho74~Tz9DnC-aPdt9XuLu z(z&PnfmlGzj-1hsyNCOd{s3`-&of6fcSa5qSL;gpJjb!UwmH8WkC*GPiuSNJRc-2r z(DeNAW?f=EU+8`a9N}L8M<|ZalVu7o&1VYX6({>~y3-#<{N6W9N%e!w9sUq;hyOTn zhkx^{o^ppzb3MM9ay|aZ;0_(J`q3zQYL>C?TRrD^lwKbx1F1>e zIiG{nt2$R!U42CEL<#Jn^*iz?%JM=q6B%U7Lifg29Hq8iM3PJCbUT*5iIkh}{Rxhq zqZfJ3vECs&D*fSnJuJ_c;8BHTE(d8c6wPro9LBN?&bivYL*RMg+~be$Vxp7~8-m!) z4uJfS9)zDP< zWoW|3NVhS5s(jwbO6y@jc)tBDPw)}ftF9bz{h@TkH3%z5ycUG&m_IZOpKE{MO#s8n zq1G@g9cm53%Au}>As_5NAt0=rM=pxRON?TvNsQFcJbHBguh4u^YfB*ZRVDvR$ z0*Jpj4@^g41|LYzKoahmINdp;Z{DLnJN*-+aDZ*cwap{V(9t`TB>1p<_h74W^qxG` zLvlc&gO5K6!+Thpqjz_A4z|u6eIiwT#@%iLWyC)TWyCR7WOWipeW=n3-||D%KgFtu zf0|SgKm7Eeip;Q|+RHq(mk9v2Hz}=k@P4dUH_Ywlk?I*V-SU|g zJ^wmB~jHa^!o~nncf2QW4 zswx2dOZQ%~Qfo-~H=k-trm%BJqo zNwbD^-|9KUnO!|n?r@aJdsCSVN=(ib{c|ms6J%K=Ghy2{qeQ&?+A?%idto#Pg#%cT z4hGXK7ow?OnWEfkvK~g04Rx42eeOwCXB!ZeUj*{~ypZFn5^lAA^=L}i4y1$5KXAW&Pi}U?(_ad~SKLXD88xQHla=kF`Pvj(W z{07tU2>;(7#1W#1|BKAq{wVRbf020GduJXoZ~L5BySA~`(fPtChSP+zd*SLBfs@SB zQLz_faz*T?Q;HpuNodqLPlJdG_`f6P#W)>CqkWDR9~EMnPza|`ib5h>x{}XlCmR#H zGD84waX|zsJ;7wU9Y;BWg>FApcE-^_Tz!)%J8iW8P8=lxMV^*X90mjNVt`-T2*Sj_ zII;aH@g9|rPH`HFuD*8f za+al8ORU|y5shU!<=`u%t`Q#za=G5Sa*@t_({{r@Z1t{RS1c*W1VIUG3nQP zS4ANdf;piXjung6A@xOjg9l6K@=`6BS|*BLL$WN=Yu`bb=pO&YsLYYMcqZ(!gkW$!@t=`qV$Ye0)S;$I?uSUZa@zG#=TV`TyD4MH+=0nLV#A$IUK=LL&zB+gd zHF1NfRD#i{{;sPyDyCQcL%By2aD}?1;o5DWtXx?!5l84kNdkMu!7siRWm zmOhZokQ76!&rz6F#^TDiohUD4Mi~(~_ACvmv(Wd+zXRd$C{&F9O_6Z*&Hrflw@EzR ziIQgHzMS;WoqPZL8_QxztR-i*5nYmNWfZF6NbR3H*C;J-#z4=1%MmNSaE@kleY(9l z-F8Ao6YLPq1Nml)ei$UfSZ2*dolhb!f~;6%=DtmTlqOcwR?k&8(|;e{ax&e{r`vtS zq3QNKsXo})vCQ*eM`ubwSz1dX&NspPc7!^c$qB0R7h#MICX+jxWFqHxE1cH;g#rvAWro&D2 zT=56>v!!X~G8y*uu+E-2Yf$-eN?UEtutKBusT^UfsU77=eKi`khv_(o)K&oq8aEXj zqI)GEhz&(LbOg`G3V>*2mZ=Gry$VoNei}sS)p6(b3gqya%5n{aPzVr+GRJHN{icdS z6T2&!%qKeV;@UlD7x3YB1F96tZqdkPVIy$zM?Im&o!bo^n2aj>JAqGT64jRaDz+{4 zFLsuOht>t%5CS!mbZ->_(JjqE(ctS02I({@5Ku5EQ~r16_R2%*CnErjixp7oqOBfxp&$F z1euJLT7@s%ra>}YBCKoG$Hvh#j_2cwUD-n-jM)d0vyOxecI-D9Iwa{(<#j33)t6*} z3}}P_R7>k}JOX<}bWr)4IIV_8h!@T^?oiY(I|T_~YUR{w{|{N2$XF)O~Vr!Mk4+ zGI-#6ScKpURWVbvc8k7?i;F^Mk|PanI*A5ikY>2G(}aS#t1#(kX^*}Vd-3CnxP}PY zO6^NMv}Si9n)1F_5m3fWVtId>xA)>;`~3UuhHw;E?irc{gZA$2qqzo^1@8vUdqpgY z(>zhye0@wj2FrXJq{%4SDG{i1?`zzl$c$IgY}{<*)9rCoIPx4fA_EQ8U}n-|e&zn@8*eClYDCG)U%m z0l6tJ6qPkoIDgdk-C5(;|!jN~-lKj$4YFYPCu;fnbFbV_|H2y z3;$~|Ol>Np8_;p)HSljkEDX+gG?dC?I5xb5M|Nysxb zA0GgM{s)|wBERaUMIId{J>~oMIzM*OfRt)l-LU0rcM=Wk<)kNUpqicIYn1EPDCBv^D>rwkIoB%R!j4ix-@|52>2dC2DizG0EjhRl)(m6|b8Jn5 z{WuMVt5~m(>PsSm?9ZLvR#!FT2i2JtCFsAylH9(;iPf47wLUg%VZmgm4@~5|S=1eh zV_YTGn?%i06zTErk(tCEvE=cwMfg$1Psj&23|Qt21SGU2RRr6n>FT*bNMszQmoMIA z{XS&z(e~`}b;m#kgsH|9OP4(@T1yXpNCuQDg4Btc%+P7nAaN5sc@ZS91^FB~L+5fG zGLD?eHI9$~db(ycoQnUQgP?$NFnC}jH8`q9lCz1XS>yxasJj+Juu3Re zgOZvIsD)Z|@^=NwjXHSy1n}{qkmY&RTEF-RG?`{Q%*mE1+jV?lVwJFt24+Y)Yb4^y z%@8+_L6+?3GdA4c9lg~wwIQkBZ~|*~+9PZRF;O1x4m)BEt*vf;RrzKneejlXJj$Td zBHMGslug!tK^{s)!1T+W;`v$&1JfgEAdZ0&{=6+(fODzG2D1#E0hT2@Fz81EEIs8Y z_S38jg|%x{ZvG33M+P7&wWVI&gQ8J;JIJJ#^NHQ^7fm=vzdPnU{4`>wqV5~o6JJ4g z(^h(tuxe_jRbqi=ICvATC`){p<5jpA zu27cUO#hx40^35g{RO&9Q|vmc(~8`Z}+YYvQ77cE7Fr9S2+Q^y;w! z!_@fI?r$AzeWh1pN1CC!f7E-&0;gQE)7LM*rjNAyy`1C7)}dQnSLlg_UVGtS>+S9^ zj_v&!TJxWFzxrrnI@(z1efz?}*4KJfo%3ueb{2XY6*#J`)|I-y)%~OLyvbO`RMF$r0E0FDw=^;Qk7bNtu8)l!LO|9?kewtCkGXr(@4XLZ9uV;UWP<+nJ!_J`x zAnerReAuZ)->_5K7LAi(htf3JbrB*~ex+>=J2PPrc1r8Fue8NsXBIB1p1r*cJJW+#zwE||6I;!yOUWb-5?RE-b{mg9yZK&J z48nH0n`i$Ldzbvna%|^EyZ;`z=Sn(-k+1 zppdm)n~)N^?@poowOZmz9PH#yD?N?ep%$P{y6JUIL$2XRRchPEQ8K-cg!6GUAOmXM z#Z`Rh*x$9=Lz=f7CTeC2H=17+tEg^#F=uHC@GjL#oVce&G2Pt z_{xe|IS#g=VOQ@fs$`S~KDfvR&y;|ne7kjzyEYs+D3V2)yq zdqYVw45hyy+av=PvC(rx2aN|P+gUW+k$siZ-JFKzqVr*~lr$P;(R~Ty>+>u(DS0fT z_?aj!$voOgmfvnRd^gI9X%P3L32dfEzIS!$W9?i%#vO>Y>u0ZTT)wilrLl@9cKjJx z1n);cBnK|ur`p-9UDw0gx(_u4a@3nO34E-b2C(j7CStZ{R`6yAL#(o6R^`$*9^Syh zt{+W~RUHsfhA4X0eJuebI>?j*Xd=dtmeFL}tw@(Lc8Ddb*qQ z@i^o77=Y@UVOjF0E6;Ttsych13W3)Ls-TN;kKWz0X+o+U9?}fqu1uxmwxe3DA_@rx z+MXY8nTia{p@jwpq;DCtOs-uCiW-1BN;8+OB4$$vC8YZ zeeRB};;F2#Z2p8(u^YsZdy}ctf&DLSqVKR{u0Hk>#GOOec$C0*DHzLwb5u^!Jdd_x z*%s?byf4NwK-z%OG}aI!M_||$1#z72$)RH=?J)^2IZT2M3OI*Z(BNAk3|JB3BWW7T zV1{E8-Sq@SIbgg|tY(t{VS0;3A{)DirTmB02GsKgKKiP?@E!Nmk8tv^TQf`%)oV9` z%YXS)(Oj{U?eX1Vr0l7(Y0?kVv1|QD^;oXY<7iiA{d6~XY^&)zKj7v4G%0^!dA-jR zzWg!Baew3ZDJHO7A>Ga4b5~5=5e+QW(1l&395$CvzWwcQXN~~aIZXRQIf>I+53)=2 zg-~z(W1B*;bt~e=G)utU0VjEBE!Pl`7n7TLpun+_mqV@Wl1webccQoy3Y!2TVs`{f zmf}TU3Tba#?p(U%qXISI$AHB%XU?1v8<#gPzI^%8&8utIUJ{osU%$G3OV9@zg!?^} z3*#C^2tYqu6h)zq<)EDpLOGnq>X{>x`tSZw#=*XNPiFwz4rH8{C@#-4MS_Mwx+~p% zHlumSYCBWKfYH>?Wx-yq+I0}yT|rcgyu9MyfR+$3MxRM{b7ivG7HcC!))=OeJ^RU$ zvqgJq#7bz!^CF#09L2wT{S4Ca82GR%76<8gvLh35W*|N(b}~6}hFsKmN=phyQ4HFf z=Iu#PgzZ<;h|esfJvx*vvB=BAsThoh?L1Uo^C*=^QGz+`FHUuk4EuXQR5aD()Yj<( zU$xe;lUn7u&8Pz3|5c(pHM~8_BpPCAtN!Hs>gO7E7DW!yp{#2r??(l`)iJ6lc`;0< zMR_p(bxs?ZWi@SNmN^h+!yoS=^-rU^<1ec1caY0RCrw&D)?37s-(G{Q_kn3 ziW%5B4K74ve1_?$IF*0Ug%wVgp-(WEYdGS8V+?=96N4+;KPeA+FnHXVhXMzJd@ZZz zg?6u>CVgVoR_Ow-*0SdXQ=fBA+%rN|=ba66E~w`0^N<(nEa-ZC2Fz|Qv7@weH6C%p z=`8{Ht}bVkqirFz^tbSfNbGoTEqc4fY#mK`&eowg+sD=CZ6Au>Lase~3sqerX{PRj zk+Lg66iX6Fs3Vc?=4aHYPm@PYzfc@vG0DZ5j=nY1-F&#MhPEQm(eQ`bDmL=Xg+}ho zkB&`VtD_>7*XU@tRc`WNC`P?#q;l_(M~YyCT&^O7E&;N|THGY-LzVz=LCRsf-CkT4 zO3z7bC3(hcDW>LTRnBk_82Gk2%jyZ|QYE4vFk3yr&(0VYNWK^wnIuD1?I9v(uvt~>hF#5y)fE}qi&f8*F?64|}%QJ2XF1C#Y zJ}IpimzVABVgP?MQm2OJWxTm)oj3KP6Fa}zQK_BZ>S*My(&oYF-L+KYQ^XXGi(n!W zSq$aw#}izv!DKQh;uUpx>HTfEqM2;g@4!qsVMVFiFFJ zL(w5c4RZpd&S+9Fj+a3 zudwFdM++2Z2h;(=1L0iSXepx|iNH9Ap4PTeJ84#D{&6&73I&s$!JCVk`g1=zIW4t2 zDm^VVI~qZ)HhM6M>hn_Cr(`UPFx5I)XCEIA-LwV@ij*;}wEUooS7h!RuLs7@$y2lWttU&2pDU{f*+1Dd#{tEKeS$d*YL#fT8r6M4Y~00d%xu zV(0qiIwE%7M?W4;o1-2Lr^(Tdh2P-8js(Y2+6!gEOg^#m6?`FE7G^Z;rlSy+J_t7f z+#RO3o#&la@VB)ni@X%WgShjB`C z{bOV%L;bFQZ1cu6Nu(3Zsz~wJs%AJ8+j5j<`fq?KDzJM0qBj=@Ic=0;iW~c$vH>Wr zA8npx-f-3IOpgfL&4HT0Ce^(}s}}UxJVu-Lklr$m)if@>6Y^8zthc1Amphx6FIoMt zF0}VYefd#fv{$SynqSg?qnJMwe?zFCF;gLfYd|nZ^(*61jU$yApq|owp;XRLU^6K+ z6QT(}_*)DU;v=Y>EeLdRRFdgr4x#h3k?CYEd1E@ZN(-Gs)U+xY@IW;tWfmrfn4dUw zgj_^^ob2Zj)ZaZ!{ATMs6l=Tu-pPgDH!g5;gPI2BU0B!e?spFkW_54pqO145aiRC3 z^7*KC?^yqT6IFXp{j@7$kM6$v+r5(uGpA!;c})FJcYpC<>l^Av(RNFw@|Et!!PYm| zS9YIaO@pMnf3USw-=O^DY8oBDF#`S$Rrt_ZFcmku!OY&v)+MGjm zB>yp^a`U@1Q}Rl!&x)y<=OJRhmj=wko4G{Fh(-EXr24g(jivJ(=^#uWUO9BQyRwuX zGta}W+{a+}RHT%N2#ST{4`Ze@%X@?N)vkV4HHDjpSCq-_;gtv-j!=#F_6QYu&yG~_ zuGHBwp&Zkq7^!tzZzdNK6lG37$mB3z!2{t?CPfs)IV0$JJWb%1D6K_*HWp2UFjx72 zfK=$Mg!%ehvL#N))lPx+`DLwn~K3g(!1nPBq@YywEWW!MG}1{ysZ1$ zhczx}gx_gDK>DWY@6?%0c2!rUMs)YP9xy003CiaZOd|c2zL<{`rKcZE;6YZ+$)luJ zBB9l<${L_QNI>h(m3n3avD$A+xi_<4{arUUJu{7;$czGgQMweF7uH^$7Q8KYqD0x| z_rXrqE{$vPBoC>ir!%wK5Hl+0qF@Y|`6Y9|m<3WJr24@VR+y%DT@!SUFrx6S{CtC- z9euCG%jI@HiKC*~5Uzr0U?Y6T<)p$iu zL;dYSLQRk`pPGWu63OSi!Kf{f#=|~E^=^qo?(sis>c{RBPZ_Y$xcj?|EdG^3oG zsX**u5tw*7K_O%?2nEp3EC79Q#$MuzqTF|F8idHuJ0zPe_%AEQsQo^XCh@$iK$==` z0AyM#Et7T3q&W}Myued?W7%1-W00XJo)h>|!O=j+0@FivfU^WR;S1@zPw{ zve-$4BZ*O3T+dAsX9Nc|An(vcu`Eu_GeFUgXX*^}0nAp(8BaO%8t|eJ(Q+O`y^re5 zurHqZB4b6Jsjc;NWcSc>ChH@YM+h>?K;{AsDH&r5d1I04$%0faYr%081PTVo11pEK z%`*x9xNy|N>Eqb@ip%AZ{0%pHZ9Hbfo0Z&WLOg`#6FG>2m`G=kxWc6+IAEcZbWb$n zfE;8k)tF8Yhg(aqEzxebEhewQ$9RyAWv<);FJBVD2tDAA;wX^l8h<%Ltq6l$Y~%DY zlj)=zbNTZxwmYLad8MNA-O^|8C`=7_@Q-=6%XdfwN}Pp7maUbKd3 ztK*8HS}i$5GEGvvX^HsIH=hZ0l6lZq5>k*|8A^smi+&>*5$9k&IJ|-1j4kGC8>&w; znyAx-T&hgz+f-P5+_nDN@Y_Z$OOr-v0Q(1IQL&87h1LH?+&8x z)QtX+J3zardGpfb{BNsJgIL`>AP(uD83qEsLC=bwk9sm&q_NXw?d=IJ|H_+RaXR$7 zw7cF?GNER=S@`o0jBRVCELK;=;`56(Ni-FzIETO)BB?grcB~Y0jS>=~?C{fzSS>%s zv^%{bRSz?_ZC3z|2AP#GbWxgETU{w)8#U*MXs3UjpbSaUrH)RE#Sbr@Hd8z;7FT?n zLusbdf@0w=x5Ok%2LQEtk!fcLOXlE&fkO+!*s)yVg=u3=n&>Y5U7p9xr5H@whvX$*939@}sYuI$AeqWU#XLJ>2$-{Ormg8-i z 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 Hk=OnoAT#94 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.47.0

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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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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.netns.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.netns.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4c231727814e0e4de256eff89a04222edcef3f96 GIT binary patch literal 152253 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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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 literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.ns3.doctree new file mode 100644 index 0000000000000000000000000000000000000000..dd6ab1b45f3419d2aae91a6fb06443ff5a9586bf GIT binary patch literal 377819 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 >`W-4l0UE^ww00=xJsR0=ek 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 wVIt}}c_(=oBX3%1p{|~Qn+zuYKg*KqzW@LL literal 0 HcmV?d00001 diff --git a/doc/sphinx/_build/doctrees/_layout/nepi.resources.omf.doctree b/doc/sphinx/_build/doctrees/_layout/nepi.resources.omf.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ee74928bc76e062a91da170e3070f9821cf10d74 GIT binary patch literal 373627 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