From 1ce40ff6bf01ed8257316ace03a46f165114149b Mon Sep 17 00:00:00 2001 From: Alina Quereilhac Date: Fri, 13 Feb 2015 13:52:54 +0100 Subject: [PATCH] Adding examples/ns3/multi_host --- examples/ns3/multi_host/case_a.py | 93 +++++ examples/ns3/multi_host/case_b.py | 79 ++++ examples/ns3/multi_host/case_c.py | 70 ++++ examples/ns3/multi_host/code/agent.c | 53 +++ examples/ns3/multi_host/code/transmitter.c | 46 +++ examples/ns3/multi_host/experiment.py | 379 ++++++++++++++++++ .../multi_host/experiment_interconnected.py | 47 +++ ...experiment_interconnected_ns3_planetlab.py | 96 +++++ .../experiment_interconnected_ns3ns3.py | 65 +++ 9 files changed, 928 insertions(+) create mode 100644 examples/ns3/multi_host/case_a.py create mode 100644 examples/ns3/multi_host/case_b.py create mode 100644 examples/ns3/multi_host/case_c.py create mode 100644 examples/ns3/multi_host/code/agent.c create mode 100644 examples/ns3/multi_host/code/transmitter.c create mode 100644 examples/ns3/multi_host/experiment.py create mode 100644 examples/ns3/multi_host/experiment_interconnected.py create mode 100644 examples/ns3/multi_host/experiment_interconnected_ns3_planetlab.py create mode 100644 examples/ns3/multi_host/experiment_interconnected_ns3ns3.py diff --git a/examples/ns3/multi_host/case_a.py b/examples/ns3/multi_host/case_a.py new file mode 100644 index 00000000..9c342267 --- /dev/null +++ b/examples/ns3/multi_host/case_a.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# +# NEPI, a framework to manage network experiments +# Copyright (C) 2013 INRIA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation; +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General 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 + +import os +from experiment imptort Experiment +from nepi.execution.ec import ExperimentController +from nepi.execution.resource import ResourceState, ResourceManager + +# Experiment parameters +experiment_id = "case_a" +agent = "10.0.1.1" +netblock = "10.0.1.0" +prefix = "24" +# number of nodes to test +parameters = [3] + +# list of hosts for running the experiment on +node_info = [ + {"hostname":"onelab4.warsaw.rd.tp.pl", + "username":"inria_nepi", + "identity": "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])}] + +# tunning +os.environ["NEPI_NTHREADS"] = "1" +ResourceManager._reschedule_delay = "0s" + +# == Experimentation setup ==================================================== +def main(): + # Prepare the ExperimentController + ec = ExperimentController(exp_id = experiment_id) + + # run experimentation as long as there is something to do + while len(parameters) > 0: + # Collection of application being processed + jobs = list() + + # Collection of experiments launched + xps = list() + + # Push a job on each node in the cluster + for node in node_info: + # Stop if nothing else to do + if len(parameters) == 0: + break + + # Determine what network size to test + nb_nodes = parameters.pop(0) + + # Create the simulated network + xp = Experiment(ec, node, nb_nodes, False) + xp.build_topology(netblock, prefix, agent) + + # Remember the experiments just created + xps.append(xp) + + # Remember the applications to be executed + jobs += xp.apps + + # Let's run the experiment + ec.deploy() + ec.wait_finished(jobs) + + # Check if everything went well for each experiment + for xp in xps: + # and see the output + stdout = ec.trace(xp.apps[0], "stdout") + print "[", stdout, "]" + # check if one transmitter failed (if everything goes well, all trasmitters + # must have stopped properly) (ignore the agent) + for app in xp.apps[1:len(xp.apps)]: + if ec.state(app, hr=False) != ResourceState.STOPPED: + raise Exception("Crashed at size %d" % xp.nb_nodes) + # et voila + ec.shutdown() + +main() diff --git a/examples/ns3/multi_host/case_b.py b/examples/ns3/multi_host/case_b.py new file mode 100644 index 00000000..b44c8992 --- /dev/null +++ b/examples/ns3/multi_host/case_b.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# +# NEPI, a framework to manage network experiments +# Copyright (C) 2013 INRIA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation; +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General 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 + +import os +from experiment_interconnected_ns3_ns3 import ExperimentInterconnectedNs3Ns3 +from nepi.execution.ec import ExperimentController +from nepi.execution.resource import ResourceManager + +# Experiment parameters +experiment_id = "case_b" +agent = ["10.0.2.1", "10.0.1.1"] +netblock = ["10.0.1.0", "10.0.2.0"] +prefix = ["24", "24"] +nb_nodes = [1, 1] +# list of hosts for running the experiment on +node_info = [ + {"hostname":"onelab4.warsaw.rd.tp.pl", + "username":"inria_nepi", + "identity": "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])}, + {"hostname":"planet2.servers.ua.pt", + "username":"inria_nepi", + "identity": "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])} + ] + +# tunning +os.environ["NEPI_NTHREADS"] = "1" +ResourceManager._reschedule_delay = "0s" + +# == Experimentation setup ==================================================== +def main(): + # Prepare the ExperimentController + ec = ExperimentController(exp_id = experiment_id) + + # Create the simulated network + # + # On the first machine + xp1 = ExperimentInterconnectedNs3Ns3(ec, node_info[0], nb_nodes[0]) + xp1.build_topology(netblock = netblock[0], prefix = prefix[0], target = agent[0]) + # + # On the second machine + xp2 = ExperimentInterconnectedNs3Ns3(ec, node_info[1], nb_nodes[1]) + xp2.build_topology(netblock = netblock[1], prefix = prefix[1], target = agent[1]) + + # interconnect the two experiments + xp1.interconnect(xp2) + + # Let's run the experiment + ec.deploy() + ec.wait_finished( xp1.apps[1:len(xp1.apps)] + xp2.apps[1:len(xp2.apps)] ) + + + # and see the output + stdout = ec.trace(xp1.apps[0], "stdout") + print "1[", stdout, "]" + + stdout = ec.trace(xp2.apps[0], "stdout") + print "2[", stdout, "]" + + # et voila + ec.shutdown() + +main() diff --git a/examples/ns3/multi_host/case_c.py b/examples/ns3/multi_host/case_c.py new file mode 100644 index 00000000..bd36cf77 --- /dev/null +++ b/examples/ns3/multi_host/case_c.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# +# NEPI, a framework to manage network experiments +# Copyright (C) 2013 INRIA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation; +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General 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 + +import os +from experiment_interconnected_ns3_planetlab import ExperimentInterconnectedNs3Planetlab +from nepi.execution.ec import ExperimentController +from nepi.execution.resource import ResourceManager + +# Experiment parameters +experiment_id = "case_c" +agent = None +netblock = "192.168.3.0" +prefix = "25" +nb_nodes = 1 + +node_info = { + "hostname":"onelab4.warsaw.rd.tp.pl", + "username":"inria_nepi", + "identity": "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME']) + } + + +# tunning +os.environ["NEPI_NTHREADS"] = "1" +ResourceManager._reschedule_delay = "0s" + +# == Experimentation setup ==================================================== +def main(): + # Prepare the ExperimentController + ec = ExperimentController(exp_id = experiment_id) + + # Create the simulated network + xp = ExperimentInterconnectedNs3Planetlab(ec, node_info, nb_nodes) + xp.build_topology(netblock = netblock, prefix = prefix, target = agent) + + # Create Planetlab application + app = xp.add_planetlab_client(xp.ip_ap) + + # Interconnect Planetlab and ns3 + xp.interconnect("192.168.3.128", "25") + + # Let's run the experiment + ec.deploy() + ec.wait_finished([app]) + + # and see the output + stdout = ec.trace(xp.apps[0], "stdout") + print "[", stdout, "]" + + # et voila + ec.shutdown() + +main() diff --git a/examples/ns3/multi_host/code/agent.c b/examples/ns3/multi_host/code/agent.c new file mode 100644 index 00000000..460401c2 --- /dev/null +++ b/examples/ns3/multi_host/code/agent.c @@ -0,0 +1,53 @@ +/* Sample UDP server */ + +#include +#include +#include +#include +#include + +int main(int argc, char**argv) +{ + int sockfd,n; + struct sockaddr_in servaddr,cliaddr; + socklen_t len; + char mesg[1000]; + + printf("DEBUT\n"); + if (argc != 2) + { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(1); + } + + sockfd = socket(AF_INET,SOCK_DGRAM,0); + if(sockfd < 0){ + perror("socket"); + exit(1); + } + + bzero(&servaddr,sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr=htonl(INADDR_ANY); + servaddr.sin_port = htons(atoi(argv[1])); + if(bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0){ + perror("bind"); + exit(2); + } + + for (;;) + { + len = sizeof(cliaddr); + n = recvfrom(sockfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&len); + if(n < 0){ + perror("recvfrom"); + continue; + } + if(n==1){ + exit(0); + } + mesg[n] = 0; + printf("[%s]\n",mesg); + } + printf("FIN\n"); +} diff --git a/examples/ns3/multi_host/code/transmitter.c b/examples/ns3/multi_host/code/transmitter.c new file mode 100644 index 00000000..52bb3b2d --- /dev/null +++ b/examples/ns3/multi_host/code/transmitter.c @@ -0,0 +1,46 @@ + +/* Sample UDP client */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char**argv) +{ + int sockfd,n; + struct sockaddr_in servaddr,cliaddr; + char * sendline = "coucou"; + + if (argc != 3) + { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(1); + } + + sockfd = socket(AF_INET,SOCK_DGRAM,0); + if(sockfd < 0){ + perror("socket"); + exit(1); + } + + bzero(&servaddr,sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr=inet_addr(argv[1]); + servaddr.sin_port=htons(atoi(argv[2])); + + int i; + for(i = 0; i < 10; i++){ + if(sendto(sockfd,sendline,strlen(sendline),0, (struct sockaddr *)&servaddr,sizeof(servaddr)) < 0){ + perror("sendto"); + } + printf("%d\n", i); + sleep(1); + } + sendto(sockfd,sendline,1,0, (struct sockaddr *)&servaddr,sizeof(servaddr)); + exit(0); +} diff --git a/examples/ns3/multi_host/experiment.py b/examples/ns3/multi_host/experiment.py new file mode 100644 index 00000000..34da12f2 --- /dev/null +++ b/examples/ns3/multi_host/experiment.py @@ -0,0 +1,379 @@ +# +# 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 . +# +# Author: Damien Saucez +# Alina Quereilhac + +import ipaddr +from random import randint +from nepi.execution.ec import ExperimentController +from nepi.execution.resource import ResourceState, ResourceAction + +# ######################################################## +class Experiment(object): + # ec : ExperimentController + # node: planetlab::Node + def __init__(self, ec, node_info, nb_nodes, real_time = True): + print "Experiement %s %s" % (node_info, nb_nodes) + + # remember the ExperimentController the experiment is associated to + self.ec = ec + + # define the physical machine to run the experiment on + self.add_node(node_info) + + # number of simulated nodes moving in the + self.nb_nodes = nb_nodes + + # fix the geographical boundaries of the network + self.bounds_width = self.bounds_height = 100 + + # fix the speed at which mobile nodes can move + self.speed = 1 + + # collection of simulated node (their GID) in the simulator + # nsnodes[0] is always the GID of the simulated node containing the + # access point + self.nsnodes = list() + + # collection of application (their GID) running in the simulator + # apps[0] is always the GID of the agent application running on the + # access point + self.apps = list() + + # prepare the ns-3 simulator to use for the experiment + self.add_simulator(real_time) + + # for sanity check + self.topology_built = False + + def add_node(self, node_info): + """ + Define the physical machine on which run the experiment + """ + if node_info["hostname"] == "localhost": + self.node = self.ec.register_resource("linux::Node") + self.ec.set(self.node, "hostname", "localhost") + else: + self.node = self.ec.register_resource("planetlab::Node") + self.ec.set(self.node, "hostname", node_info["hostname"]) + self.ec.set(self.node, "username", node_info["username"]) + self.ec.set(self.node, "identity", node_info["identity"]) + self.ec.set(self.node, "cleanProcesses", True) + self.ec.set(self.node, "cleanExperiment", True) + + return self.node + + def add_simulator(self, real_time): + """ + Add a ns-3 simulator on the node used for the experiment + """ + # creat the ns-3 simulator instance + self.simu = self.ec.register_resource("linux::ns3::Simulation") + self.ec.set (self.simu, "StopTime", "200s") + # + # run it in realtime mode if asked + if real_time: + self.ec.set(self.simu, "simulatorImplementationType", "ns3::RealtimeSimulatorImpl") + # + # log additional information + self.ec.set(self.simu, "checksumEnabled", True) + self.ec.set(self.simu, "verbose", True) + self.ec.set(self.simu, "enableDump", True) + self.ec.register_connection(self.simu, self.node) + + return self.simu + + # == ns-3 simulation helper functions ===================================== + def add_nsnode(self): + """ + Create a ns-3 node and add it to the simulator + """ + # create a ns-3 node + nsnode = self.ec.register_resource("ns3::Node") + # enable its network stack + self.ec.set(nsnode, "enableStack", True) + self.ec.register_connection(nsnode, self.simu) + + return nsnode + + def add_wifi_channel(self): + """ + Create the WiFi channel on which all nodes will be connected + """ + # create a channel + channel = self.ec.register_resource("ns3::YansWifiChannel") + + # specify the delay model + delay = self.ec.register_resource("ns3::ConstantSpeedPropagationDelayModel") + self.ec.register_connection(channel, delay) + + # specify a loss model + loss = self.ec.register_resource("ns3::LogDistancePropagationLossModel") + self.ec.register_connection(channel, loss) + + return channel + + def add_wifi_device(self, node, ip, prefix, access_point = False): + """ + Add and configure the WiFi interface on a simulated node + """ + + # create the WiFi network interface + dev = self.ec.register_resource("ns3::WifiNetDevice") + + # specify the network layer parameters + self.ec.set(dev, "ip", ip) + self.ec.set(dev, "prefix", prefix) + self.ec.register_connection(node, dev) + + # specify the MAC layer parameters + # + # can be in access point mode or not + if access_point: + mac = self.ec.register_resource("ns3::ApWifiMac") + else: + mac = self.ec.register_resource("ns3::StaWifiMac") + # the MAC is IEEE 802.11a + self.ec.set(mac, "Standard", "WIFI_PHY_STANDARD_80211a") + self.ec.register_connection(dev, mac) + + # specify the physical layer parameters + phy = self.ec.register_resource("ns3::YansWifiPhy") + # + # it physical layer is IEEE802.11a + self.ec.set(phy, "Standard", "WIFI_PHY_STANDARD_80211a") + self.ec.register_connection(dev, phy) + # + # specify an error model for transmissions + error = self.ec.register_resource("ns3::NistErrorRateModel") + self.ec.register_connection(phy, error) + + # specify the Wifi manager to be assocated with the interface + manager = self.ec.register_resource("ns3::ArfWifiManager") + self.ec.register_connection(dev, manager) + + return dev, phy + + def add_random_mobility(self, node, x, y, z, speed, bounds_width, bounds_height): + """ + Create a mobility model for node with random movements + """ + 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 = self.ec.register_resource("ns3::RandomDirection2dMobilityModel") + self.ec.set(mobility, "Position", position) + self.ec.set(mobility, "Bounds", bounds) + self.ec.set(mobility, "Speed", speed) + self.ec.set(mobility, "Pause", pause) + self.ec.register_connection(node, mobility) + + return mobility + + def add_constant_mobility(self, node, x, y, z): + """ + Create a mobility model for node with a constant position + """ + mobility = self.ec.register_resource("ns3::ConstantPositionMobilityModel") + position = "%d:%d:%d" % (x, y, z) + self.ec.set(mobility, "Position", position) + self.ec.register_connection(node, mobility) + + return mobility + + def create_simulated_node(self, ip, prefix, channel, access_point, x, y): + """ + Create a simulated node connected on a WiFi channel + """ + # Create the ns node that will run the application + nsnode = self.add_nsnode() + + # Add a WiFi interface to the node + dev, phy = self.add_wifi_device(nsnode, ip, prefix, access_point) + # + # Connect the access point to the WiFi network + self.ec.register_connection(channel, phy) + + # Specify that the node mobility + # + # access point is not mobile + if access_point: + mobility = self.add_constant_mobility(nsnode, x, y, 0) + # other nodes have random mobility pattern + else: + mobility = self.add_random_mobility(nsnode, x, y, 0, self.speed, self.bounds_width, self.bounds_height) + + return nsnode + + def add_route(self, nsnode, netblock, prefix, nexthop): + """ + add a route on ns-3 node nsnode for netblock/prefix via nexthop + """ + route = self.ec.register_resource("ns3::Route") + self.ec.set(route, "network", netblock) + self.ec.set(route, "prefix", prefix) + self.ec.set(route, "nexthop", nexthop) + self.ec.register_connection(route, nsnode) + print "route %s/%s via %s added on nsnode %s (%s)" % (netblock, prefix, nexthop, nsnode, self) + + return route + + def add_vroute(self, dev, netblock, prefix, nexthop): + """ + Add a route on Planetlab node for netblock/prefix via nexthop + """ + route = self.ec.register_resource("planetlab::Vroute") + self.ec.set(route, "network", netblock) + self.ec.set(route, "prefix", prefix) + self.ec.set(route, "nexthop", nexthop) + self.ec.register_connection(route, dev) + print "Vroute %s/%s via %s added on nsnode %s (%s)" % (netblock, prefix, nexthop, dev, self) + + return route + + def add_agent(self, nsnode): + """ + Add a agent application + """ + # Create a DCE application running the agent code + app = self.ec.register_resource("linux::ns3::dce::Application") + self.ec.set(app, "sources", "code/agent.c") + self.ec.set(app "build", "gcc -fPIC -pie -rdynamic ${SRC}/agent.c -o ${BIN_DCE}/agent") + self.ec.set(app, "binary", "agent") + self.ec.set(app, "arguments", "45005") + self.ec.set(app, "stackSize", 1<<20) + self.ec.set(app, "StartTime", "10s") + self.ec.set(app, "StopTime", "200s") + + # Associate the application with the simulated node + self.ec.register_connection(app, nsnode) + + # Make the application start only once the simulated node is started + self.ec.register_condition(app, ResourceAction.START, + nsnode, ResourceState.STARTED, time="5s") + + return app + + def add_transmitter(self, nsnode): + """ + Add a transmitter application + """ + # Create a DCE application running the transmitter code + app = self.ec.register_resource("linux::ns3::dce::Application") + self.ec.set(app, "sources", "code/transmitter.c") + self.ec.set(app, "build", "gcc -fPIC -pie -rdynamic ${SRC}/transmitter.c -o ${BIN_DCE}/transmitter") + self.ec.set(app, "binary", "transmitter") + self.ec.set(app, "arguments", "%s;45005" % target) + self.ec.set(app, "stackSize", 1<<20) + self.ec.set(app, "StartTime", "10s") + self.ec.set(app, "StopTime", "200s") + + # Associate the application with the simulated node + self.ec.register_connection(app, nsnode) + # + # Make the application start only once the simulated node and the serer are started + self.ec.register_condition(app, ResourceAction.START, + [nsnode, self.apps[0]], ResourceState.STARTED, time="10s") + + return app + + def add_planetlab_transmitter(self, target): + """ + Add a planetlab transmitter application + """ + + # Create an application running the transmitter code + app = self.ec.register_resource("linux::Application") + self.ec.set(app, "sources", "code/transmitter.c") + self.ec.set(app, "build", "make ${SRC}/transmitter") + self.ec.set(app, "command", "${SRC}/transmitter %s 45005" % target) + + # Associate the application with the Planetlab node + self.ec.register_connection(app, self.node) + + # Make the application start only once the simulated agent and the node are started + self.ec.register_condition(app, ResourceAction.START, + [self.apps[0], self.node], ResourceState.STARTED, time="10s") + + return app + + # == Topology construction ================================================ + def build_topology(self, netblock, prefix, target): + """ + Builds a topology composed of one fixed access point and nb_nodes + mobile nodes + """ + + # Rember network parameters + self.netblock = netblock + self.prefix = prefix + + # Create the WiFi network via which nodes are connected + chan = self.add_wifi_channel() + + # == Access point + # Geographical position of the access point + x=50 + y=0 + + # the IP address of the access point is the first in the prefix + self.ip_ap = str(ipaddr.IPv4Address(self.netblock) + 1) + print "IP AP: %s " % (self.ip_ap) + + # Create the ns node that will run the access point + nsnode = self.create_simulated_node(self.ip_ap, self.prefix, chan, True, x, y) + + # add the node in the collection of simulated nodes + self.nsnodes.append(nsnode) + + # Run a agent application on the access point + agent = self.add_agent(nsnode) + + # add the agent application in the collection of applications + self.apps.append(agent) + + # Add nb_nodes mobile nodes in the WiFi network + for i in range(1, self.nb_nodes + 1): + # pic a random initial location + x = randint(0, self.bounds_width) + y = randint(0, self.bounds_height) + + # define the appropriate IP address of the node (sequential IP in what remains after the access point IP) + ip = str(ipaddr.IPv4Address(self.ip_ap) + i) + + print "IP mobile: " , ip + + # Create the ns node that will run the mobile node + nsnode = self.create_simulated_node(ip, self.prefix, chan, False, x, y) + # + # add the node in the collection of simulated nodes + self.nsnodes.append(nsnode) + + if target: + # Run a transmitter application on the mobile node + transmitter = self.add_transmitter(nsnode) + + # add the trasmitter application in the collection of applications + self.apps.append(transmitter) + + # Add a default route via the access point + self.add_route(nsnode, "0.0.0.0", "0", self.ip_ap) + + # for sanity check + self.topology_built = True diff --git a/examples/ns3/multi_host/experiment_interconnected.py b/examples/ns3/multi_host/experiment_interconnected.py new file mode 100644 index 00000000..f95bd771 --- /dev/null +++ b/examples/ns3/multi_host/experiment_interconnected.py @@ -0,0 +1,47 @@ +# +# 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 . +# +# Author: Damien Saucez +# Alina Quereilhac + +from experiment import Experiment + +class ExperimentInterconnected(Experiment): + def __init__(self, ec, node, nb_nodes, real_time = True): + super(ExperimentInterconnected, self).__init__(ec, node, nb_nodes, real_time) + self.interconnected = False + self.fddev = None + + def add_fdnetdevice(self, ip, prefix, nsnode = None): + # Sanity check + # + # only one FD device allowed + if self.fddev: + raise Exception("A FD device is already setup") + + # Attach the FD device to the access point by default + if not nsnode: + nsnode = self.nsnodes[0] + + # Create the FD device + self.fddev = self.ec.register_resource("ns3::FdNetDevice") + self.ec.set(self.fddev, "ip", ip) + self.ec.set(self.fddev, "prefix", prefix) + + # attach it to the simulated node + self.ec.register_connection(nsnode, self.fddev) + + return self.fddev diff --git a/examples/ns3/multi_host/experiment_interconnected_ns3_planetlab.py b/examples/ns3/multi_host/experiment_interconnected_ns3_planetlab.py new file mode 100644 index 00000000..01f8bcd5 --- /dev/null +++ b/examples/ns3/multi_host/experiment_interconnected_ns3_planetlab.py @@ -0,0 +1,96 @@ +# +# 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 . +# +# Author: Damien Saucez +# Alina Quereilhac + +import ipaddr +from experiment_interconnected import ExperimentInterconnected + +class ExperimentInterconnectedNs3Planetlab(ExperimentInterconnected): + def add_tap_device(self, node, ip, prefix, pointopoint): + """ + Add a point-to-point tap device on the planetlab node. This tap device + is used to exchange traffic with the simulated network + """ + # Create the tap device + dev = self.ec.register_resource("planetlab::Tap") + + # Define the local network associated with the TAP device + self.ec.set(dev, "ip", ip) + self.ec.set(dev, "prefix", prefix) + + # Define the other side of the tap (the simulated network device) + self.ec.set(dev, "pointopoint", pointopoint) + + # Associate the TAP device with the Planetlab node + self.ec.register_connection(node, dev) + + return dev + + def connect_with_tuntap(self, tap): + """ + Connect the simulated network with the Planetlab node via the TAP of + the Planetlab node and the FD device of the simulated network + """ + # Create the link + crosslink = self.ec.register_resource("planetlab::ns3::TunTapFdLink") + + # Associate it with the Planetlab tap device on one side + self.ec.register_connection(crosslink, tap) + # + # Associate it with the simulated network FD device on the other side + self.ec.register_connection(crosslink, self.fddev) + + return crosslink + + def interconnect(self, netblock_pl, prefix_pl): + """ + Interconnect a simulated network with a Planetlab network via a tap device + """ + # sanity checks + # + # topology must be setup + if not self.topology_built: + raise Exception("Topology not setup on ", self) + # + # experiment cannot be interconnected to another experiment + if self.interconnected: + raise Exception("Experiment already interconnected on ", self) + + + ip_simulated = str(ipaddr.IPv4Address(netblock_pl) + 1) + ip_pl = str(ipaddr.IPv4Address(ip_simulated) + 1) + + # Add a TAP interface on the Planetlab machine to connect the real + # application with the simulated network + tap = self.add_tap_device(self.node, ip_pl, prefix_pl, ip_simulated) + + # Add an FD device on the simulator to connect to the real + self.add_fdnetdevice(ip_simulated, prefix_pl) + + # Connect both Planetlab and simulated network via the tap device + self.connect_with_tuntap(tap) + + # Route traffic for the Planetlab node to the Planetlab machine + self.add_route(self.nsnodes[0], netblock_pl, prefix_pl, self.ip_ap) + + # Route traffic for the simulated node to the simulator + self.add_vroute(tap, self.netblock, self.prefix, ip_simulated) + + # Sanity check + self.interconnected = True + diff --git a/examples/ns3/multi_host/experiment_interconnected_ns3ns3.py b/examples/ns3/multi_host/experiment_interconnected_ns3ns3.py new file mode 100644 index 00000000..ab2a8a2c --- /dev/null +++ b/examples/ns3/multi_host/experiment_interconnected_ns3ns3.py @@ -0,0 +1,65 @@ +# +# 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 . +# +# Author: Damien Saucez +# Alina Quereilhac + +from experiment_interconnected import ExperimentInterconnected + +class ExperimentInterconnectedNs3Ns3(ExperimentInterconnected): + def connect_with_udp_tunnel(self, xp_remote): + # Connect the two experiments via a UDP tunnel direcly on the FD devices + tunnel = self.ec.register_resource("planetlab::ns3::FdUdpTunnel") + self.ec.register_connection(tunnel, self.fddev) + self.ec.register_connection(tunnel, xp_remote.fddev) + + return tunnel + + def interconnect(self, xp_remote): + """ + Interconnect two ns3 simulations via a UDP tunnel + """ + # sanity checks + # + # topology must be setup + if not self.topology_built: + raise Exception("Topology not setup on ", self) + if not xp_remote.topology_built: + raise Exception("Topology not setup on ", xp_remote ) + # + # experiment cannot be interconnected to another experiment + if self.interconnected: + raise Exception("Experiment already interconnected on ", self) + if xp_remote.interconnected: + raise Exception("Experiment already interconnected on ", xp_remote) + + # IP for the AP of the two experiments + # XXX DSA: ugly + ip = ["10.0.0.1", "10.0.0.2"] + + # add an FD device on both local and remote experiments + self.add_fdnetdevice(ip[0], "30") + xp_remote.add_fdnetdevice(ip[1], "30") + + # Connect the two experiments via a UDP tunnel direcly on the FD devices + self.connect_with_udp_tunnel(xp_remote) + + # Add a route to the remote network on each experiment, via the FD device + self.add_route(self.nsnodes[0], xp_remote.netblock, xp_remote.prefix, ip[1]) + xp_remote.add_route(xp_remote.nsnodes[0], self.netblock, self.prefix, ip[0]) + + # Sanity check + self.interconnected = True -- 2.43.0