#!/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 . # # Authors : Julien Tribino # Alina Quereilhac # # Topology : # # Switch1 ------ Switch2 ------- Switch2 # / | \ # / | \ # / | \ # Host1 Host3 Host2 # # # Execution example: # # $ PYTHONPATH=$PYTHONPATH:src/ python examples/openvswitch/ovs_ping_3_switches.py -n "192.168.3.0/24" -C "1.1.1.1" -s -i /~/.ssh/id_rsa # from __future__ import print_function from nepi.execution.ec import ExperimentController import os from optparse import OptionParser import sys import time def add_node(ec, host, user, pl_user, pl_password, identity): node = ec.register_resource("planetlab::Node") ec.set(node, "hostname", host) ec.set(node, "username", user) ec.set(node, "identity", identity) if pl_user: ec.set(node, "pluser", pl_user) if pl_password: ec.set(node, "plpassword", pl_password) if identity: ec.set(node, "identity", identity) ec.set(node, "cleanExperiment", True) ec.set(node, "cleanProcesses", True) return node def add_ovs(ec, bridge_name, virtual_ip_pref, controller_ip, controller_port, node): ovs = ec.register_resource("planetlab::OVSSwitch") ec.set(ovs, "bridge_name", bridge_name) ec.set(ovs, "virtual_ip_pref", virtual_ip_pref) ec.set(ovs, "controller_ip", controller_ip) ec.set(ovs, "controller_port", controller_port) ec.register_connection(ovs, node) return ovs def add_port(ec, port_name, network, ovs): port = ec.register_resource("planetlab::OVSPort") ec.set(port, "port_name", port_name) ec.set(port, "network", network) ec.register_connection(port, ovs) return port def add_tap(ec, ip, prefix, pointopoint, node): tap = ec.register_resource("planetlab::Tap") ec.set(tap, "ip", ip) ec.set(tap, "prefix", prefix) ec.set(tap, "pointopoint", pointopoint) ec.set(tap, "up", True) ec.register_connection(tap, node) return tap def add_tunnel(ec, port0, tap): tunnel = ec.register_resource("linux::UdpTunnel") ec.register_connection(port0, tunnel) ec.register_connection(tunnel, tap) return tunnel def add_app(ec, command, node): app = ec.register_resource("linux::Application") ec.set(app, "command", command) ec.register_connection(app, node) return app def parse_args(): pl_slice = os.environ.get("PL_SLICE") pl_user = os.environ.get("PL_USER") pl_pass = os.environ.get("PL_PASS") identity = os.environ.get("PL_SSHKEY") usage = ("usage: %prog -a -b -c " "-d -e -f " "-n -C -s -u " "-p -i ") switch1 = "planetlab2.virtues.fi" switch2 = "planetlab2.upc.es" switch3 = "inriarennes1.irisa.fr" host1 = "planetlab2.ionio.gr" host2 = "iraplab2.iralab.uni-karlsruhe.de" host3 = "planetlab2.diku.dk" parser = OptionParser(usage = usage) parser.add_option("-a", "--host1", dest="host1", help="Hostname for PlanetLab host 1", default=host1) parser.add_option("-b", "--host2", dest="host2", help="Hostname for PlanetLab host 2", default=host2) parser.add_option("-c", "--host3", dest="host3", help="Hostname for PlanetLab host 3", default=host3) parser.add_option("-d", "--switch1", dest="switch1", help="Hostname for PlanetLab switch 1", default=switch1) parser.add_option("-e", "--switch2", dest="switch2", help="Hostname for PlanetLab switch 2", default=switch2) parser.add_option("-f", "--switch3", dest="switch3", help="Hostname for PlanetLab switch 3", default=switch3) parser.add_option("-n", "--vsys_vnet", dest="vsys_vnet", help="Overlay network address of the form x.x.x.x/yy. " "Must correspond to the vsys_vnet tag on the PlanetLab slice") parser.add_option("-C", "--controller", dest="controller", help="IP address for the OpenFlow controller, if one has been deployed", default="1.1.1.1") parser.add_option("-s", "--slicename", dest="slicename", help="Name of PlanetLab slice", default=pl_slice) parser.add_option("-u", "--pl_user", dest="pl_user", help="PlanetLab user (email address)", default=pl_user) parser.add_option("-p", "--pl_pass", dest="pl_pass", help="PlanetLab password", default=pl_pass) parser.add_option("-i", "--identity", dest="identity", help="Path to SSH key", default=identity) (options, args) = parser.parse_args() return (options.host1, options.host2, options.host3, options.switch1, options.switch2, options.switch3, options.vsys_vnet, options.controller, options.slicename, options.pl_user, options.pl_pass, identity) (host1, host2, host3, switch1, switch2, switch3, vsys_vnet, controller, slicename, pl_user, pl_pass, identity) = parse_args() # Create the EC ec = ExperimentController(exp_id = "ovs_3_switch") net = vsys_vnet.split("/") prefix = net[-1] network = net[0] net_segs = network.split(".") ip1 = "%s.1" % ".".join(net_segs[:-1]) # x.x.x.1 ip2 = "%s.2" % ".".join(net_segs[:-1]) # x.x.x.2 ip3 = "%s.3" % ".".join(net_segs[:-1]) # x.x.x.3 ip4 = "%s.4" % ".".join(net_segs[:-1]) # x.x.x.4 ip5 = "%s.5" % ".".join(net_segs[:-1]) # x.x.x.5 ip6 = "%s.6" % ".".join(net_segs[:-1]) # x.x.x.6 ### Define topology # Add switches s1_node = add_node(ec, switch1, slicename, pl_user, pl_pass, identity) s2_node = add_node(ec, switch2, slicename, pl_user, pl_pass, identity) s3_node = add_node(ec, switch3, slicename, pl_user, pl_pass, identity) # Add OVS switches addr1 = "%s/%s" % (ip1, prefix) # x.x.x.1/prefix addr2 = "%s/%s" % (ip2, prefix) # x.x.x.2/prefix addr3 = "%s/%s" % (ip3, prefix) # x.x.x.3/prefix ovs1 = add_ovs(ec, "nepi_bridge_1", addr1, controller, "6633", s1_node) ovs2 = add_ovs(ec, "nepi_bridge_2", addr2, controller, "6633", s2_node) ovs3 = add_ovs(ec, "nepi_bridge_3", addr3, controller, "6633", s3_node) # Add ports on ovs port1 = add_port(ec, "nepi_port1", network, ovs1) port4 = add_port(ec, "nepi_port4", network, ovs1) port7 = add_port(ec, "nepi_port7", network, ovs1) port2 = add_port(ec, "nepi_port2", network, ovs2) port5 = add_port(ec, "nepi_port5", network, ovs2) port3 = add_port(ec, "nepi_port3", network, ovs3) port6 = add_port(ec, "nepi_port6", network, ovs3) # Add hosts h1_node = add_node(ec, host1, slicename, pl_user, pl_pass, identity) h2_node = add_node(ec, host2, slicename, pl_user, pl_pass, identity) h3_node = add_node(ec, host3, slicename, pl_user, pl_pass, identity) ### Add overlay # Add tap devices tap1 = add_tap(ec, ip3, prefix, ip1, h1_node) tap2 = add_tap(ec, ip4, prefix, ip2, h2_node) tap3 = add_tap(ec, ip5, prefix, ip6, h3_node) ### Add Pings # Connect the nodes tunnel1 = add_tunnel(ec, port1, tap1) tunnel2 = add_tunnel(ec, port2, tap2) tunnel3 = add_tunnel(ec, port3, tap3) tunnel4 = add_tunnel(ec, port4, port5) tunnel5 = add_tunnel(ec, port7, port6) apps = dict() r2ip = dict({ s1_node: ("Switch 1", ip1), s2_node: ("Switch 2", ip2), s3_node: ("Switch 3", ip3), h1_node: ("Host 1", ip4), h2_node: ("Host 2", ip5), h3_node: ("Host 3", ip6), }) # Ping from all resources to all other resources for r1, (n1, ip1) in r2ip.items(): for r2, (n2, ip2) in r2ip.items(): if r1 == r2: continue app = add_app(ec, "ping -c5 %s" % ip2, r1) key = "Ping from %s to %s" % (n1, n2) apps[key] = app ec.deploy() # py3: no need to transform into a list # as wait_finished (wait in fact) will do it anyway ec.wait_finished(apps.values()) # collect results for key, app in apps.items(): stdout = ec.trace(app, "stdout") print("***************************", key, "************************") print(stdout) print("\n") # Delete the overlay network ec.shutdown()