#!/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