#!/usr/bin/env python # # NEPI, a framework to manage network experiments # Copyright (C) 2015 INRIA # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation; # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Author: Damien Saucez # Alina Quereilhac # from six import PY2, next if PY2: import ipaddr else: import ipaddress from optparse import OptionParser import os from random import randint # list of hosts for running the experiment on hostname1 = "onelab4.warsaw.rd.tp.pl" hostname2 = "planet2.servers.ua.pt" def get_options(): # PlanetLab credentials pl_slice = os.environ.get("PL_SLICE") pl_user = os.environ.get("PL_USER") pl_password = os.environ.get("PL_PASS") pl_ssh_key = os.environ.get("PL_SSHKEY") usage = ("usage: %prog -s -u -p " "-k -n ") parser = OptionParser(usage = usage) parser.add_option("-s", "--pl-slice", dest="pl_slice", help="PlanetLab slicename", default=pl_slice, type="str") parser.add_option("-u", "--pl-user", dest="pl_user", help="PlanetLab web username", default=pl_user, type="str") parser.add_option("-p", "--pl-password", dest="pl_password", help="PlanetLab web password", default=pl_password, type="str") parser.add_option("-k", "--pl-ssh-key", dest="pl_ssh_key", help="Path to private SSH key associated with the PL account", default=pl_ssh_key, type="str") parser.add_option("-n", "--node-count", dest="node_count", help="Number of nodes in the wireless network", default = 4, type="int") (options, args) = parser.parse_args() return (options.pl_slice, options.pl_user, options.pl_password, options.pl_ssh_key, options.node_count) # == add host and simu ======================================================= def add_host_simu(ec, hostname, username, pl_user, pl_password, ssh_key): host = ec.register_resource("planetlab::Node") ec.set(host, "hostname", hostname) if username: ec.set(host, "username", username) if pl_user: ec.set(host, "pluser", pl_user) if pl_password: ec.set(host, "plpassword", pl_password) if ssh_key: ec.set(host, "identity", ssh_key) ec.set(host, "cleanProcesses", True) ec.set(host, "cleanExperiment", True) simu = ec.register_resource("linux::ns3::Simulation") ec.set(simu, "simulatorImplementationType", "ns3::RealtimeSimulatorImpl") ec.set(simu, "checksumEnabled", True) ec.set(simu, "verbose", True) ec.set(simu, "enableDump", True) ec.set (simu, "StopTime", "200s") ec.register_connection(simu, host) return host, simu # == build topology ========================================================= def add_ns3_wifi_device(ec, ns3_node, ip, prefixlen, ap_mode): # create the WiFi network interface dev = ec.register_resource("ns3::WifiNetDevice") # specify the network layer parameters ec.set(dev, "ip", ip) ec.set(dev, "prefix", prefixlen) ec.register_connection(ns3_node, dev) # specify the MAC layer parameters # # can be in access point mode or not if ap_mode: mac = ec.register_resource("ns3::ApWifiMac") else: mac = ec.register_resource("ns3::StaWifiMac") # the MAC is IEEE 802.11a ec.set(mac, "Standard", "WIFI_PHY_STANDARD_80211a") ec.register_connection(dev, mac) # specify the physical layer parameters phy = ec.register_resource("ns3::YansWifiPhy") # # it physical layer is IEEE802.11a ec.set(phy, "Standard", "WIFI_PHY_STANDARD_80211a") ec.register_connection(dev, phy) # # specify an error model for transmissions error = ec.register_resource("ns3::NistErrorRateModel") ec.register_connection(phy, error) # specify the Wifi manager to be assocated with the interface manager = ec.register_resource("ns3::ArfWifiManager") ec.register_connection(dev, manager) return dev, phy def add_ns3_wifi_channel(ec): channel = ec.register_resource("ns3::YansWifiChannel") delay = ec.register_resource("ns3::ConstantSpeedPropagationDelayModel") ec.register_connection(channel, delay) loss = ec.register_resource("ns3::LogDistancePropagationLossModel") ec.register_connection(channel, loss) return channel # == Add random mobility def add_ns3_random_mobility(ec, ns3_node): speed = 1 bounds_width = 100 bounds_height = 100 x = randint(0, bounds_width) y = randint(0, bounds_height) z = 0 position = "%d:%d:%d" % (x, y, z) bounds = "0|%d|0|%d" % (bounds_width, bounds_height) speed = "ns3::UniformRandomVariable[Min=%d|Max=%s]" % (speed, speed) pause = "ns3::ConstantRandomVariable[Constant=1.0]" mobility = ec.register_resource("ns3::RandomDirection2dMobilityModel") ec.set(mobility, "Position", position) ec.set(mobility, "Bounds", bounds) ec.set(mobility, "Speed", speed) ec.set(mobility, "Pause", pause) ec.register_connection(ns3_node, mobility) return mobility # == Add constant mobility def add_ns3_constant_mobility(ec, ns3_node): mobility = ec.register_resource("ns3::ConstantPositionMobilityModel") position = "%d:%d:%d" % (0, 50, 0) ec.set(mobility, "Position", position) ec.register_connection(ns3_node, mobility) return mobility # == add ns-3 node def add_ns3_node(ec, simu, ip, prefixlen, channel, ap_mode=False): ns3_node = ec.register_resource("ns3::Node") ec.set(ns3_node, "enableStack", True) ec.register_connection(ns3_node, simu) dev, phy = add_ns3_wifi_device(ec, ns3_node, ip, prefixlen, ap_mode) ec.register_connection(channel, phy) if not ap_mode: add_ns3_random_mobility(ec, ns3_node) else: add_ns3_constant_mobility(ec, ns3_node) return ns3_node # == add DCE agent def add_dce_agent(ec, ns3_node): agent = ec.register_resource("linux::ns3::dce::Application") ec.set(agent, "sources", "code/agent.c") ec.set(agent, "build", "gcc -fPIC -pie -rdynamic ${SRC}/agent.c -o ${BIN_DCE}/agent") ec.set(agent, "binary", "agent") ec.set(agent, "stackSize", 1<<20) ec.set(agent, "StartTime", "10s") ec.set(agent, "StopTime", "200s") ec.register_connection(agent, ns3_node) return agent # == add DCE transmitter def add_dce_transmitter(ec, ns3_node, target): transmitter = ec.register_resource("linux::ns3::dce::Application") ec.set(transmitter, "sources", "code/transmitter.c") ec.set(transmitter, "build", "gcc -fPIC -pie -rdynamic ${SRC}/transmitter.c -o ${BIN_DCE}/transmitter") ec.set(transmitter, "binary", "transmitter") ec.set(transmitter, "arguments", target) ec.set(transmitter, "stackSize", 1<<20) ec.set(transmitter, "StartTime", "10s") ec.set(transmitter, "StopTime", "200s") ec.register_connection(transmitter, ns3_node) return transmitter # == Add ns-3 route def add_ns3_route(ec, ns3_node, network, prefixlen, nexthop): route = ec.register_resource("ns3::Route") ec.set(route, "network", network) ec.set(route, "prefix", prefixlen) ec.set(route, "nexthop", nexthop) ec.register_connection(route, ns3_node) return route # = build ns3 topology ======================================================= def build_ns3_topology(ec, simu, node_count, network, prefixlen, agent_ip): channel = add_ns3_wifi_channel(ec) if PY2: net = ipaddr.IPv4Network("%s/%s" % (network, prefixlen)) itr = net.iterhosts() else: net = ipaddress.IPv4Network("%s/%s" % (network, prefixlen)) itr = net.hosts() ap_ip = next(itr).exploded ap = add_ns3_node(ec, simu, ap_ip, prefixlen, channel, ap_mode=True) agent = None if ap_ip == agent_ip: agent = add_dce_agent(ec, ap) for i in range(0, node_count): ip = itr.next().exploded sensor = add_ns3_node(ec, simu, ip, prefixlen, channel, ap_mode=False) transmitter = add_dce_transmitter(ec, sensor, ap_ip) add_ns3_route(ec, sensor, network="0.0.0.0", prefixlen="0", nexthop=ap_ip) return ap, agent # == add FdNetDevice ========================================================= def add_fdnet_device(ec, ap, ip, prefixlen): fddev = ec.register_resource("ns3::FdNetDevice") ec.set(fddev, "ip", ip) ec.set(fddev, "prefix", prefixlen) ec.register_connection(ap, fddev) return fddev # == connect with UDP tunnel ================================================= def connect_with_udp_tunnel(ec, fddev1, fddev2): tunnel = ec.register_resource("planetlab::ns3::FdUdpTunnel") ec.register_connection(tunnel, fddev1) ec.register_connection(tunnel, fddev2) return tunnel # == connect with virtual link =============================================== def connect_with_virtual_link(ec, tap, fddev): link = ec.register_resource("planetlab::ns3::TunTapFdLink") ec.register_connection(link, tap) ec.register_connection(link, fddev) return link # == Add planet lab route ==================================================== def add_planetlab_route(ec, dev, network, prefixlen, nexthop): route = ec.register_resource("planetlab::Vroute") ec.set(route, "network", network) ec.set(route, "prefix", prefixlen) ec.set(route, "nexthop", nexthop) ec.register_connection(route, dev) return route