From: Julien Tribino Date: Mon, 19 May 2014 15:13:24 +0000 (+0200) Subject: Merging the openflow part to the nepi-3-dev branch X-Git-Tag: nepi-3.1.0~79 X-Git-Url: http://git.onelab.eu/?p=nepi.git;a=commitdiff_plain;h=1e2eb157cb569e9c28a5b7888ed97076d27414cb;hp=966adc0acd082b1299f851e966077be28c3fa39e Merging the openflow part to the nepi-3-dev branch --- diff --git a/examples/openvswitch/ovs_ping_2switches.py b/examples/openvswitch/ovs_ping_2switches.py new file mode 100644 index 00000000..7fbb74b4 --- /dev/null +++ b/examples/openvswitch/ovs_ping_2switches.py @@ -0,0 +1,198 @@ +#!/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 as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# 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 +# / \ +# / \ +# / \ +# Host1 Host2 + + + +from nepi.execution.ec import ExperimentController +import os, time +import sys + +def add_node(ec, host, user, pl_user, pl_password): + node = ec.register_resource("PlanetlabNode") + ec.set(node, "hostname", host) + ec.set(node, "username", user) + if pl_user: + ec.set(node, "pluser", pl_user) + if pl_password: + ec.set(node, "plpassword", pl_password) + ec.set(node, "cleanHome", 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("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, ovs): + port = ec.register_resource("OVSPort") + ec.set(port, "port_name", port_name) + ec.register_connection(port, ovs) + return port + +def add_tap(ec, ip4, prefix4, pointopoint, node): + tap = ec.register_resource("PlanetlabTap") + ec.set(tap, "ip4", ip4) + ec.set(tap, "prefix4", prefix4) + ec.set(tap, "pointopoint", pointopoint) + ec.set(tap, "up", True) + ec.register_connection(tap, node) + return tap + +def add_tunnel(ec, network, port0, tap): + tunnel = ec.register_resource("OVSTunnel") + ec.set(tunnel, "network", network) + ec.register_connection(port0, tunnel) + ec.register_connection(tunnel, tap) + return tunnel + +def add_app(ec, command, node): + app = ec.register_resource("LinuxApplication") + ec.set(app, "command", command) + ec.register_connection(app, node) + return app + +# Create the EC +ec = ExperimentController(exp_id = "test") + +switch1 = "planetlab2.virtues.fi" +switch2 = "planetlab2.upc.es" +host1 = "planetlab2.ionio.gr" +host2 = "iraplab2.iralab.uni-karlsruhe.de" + +ip_controller = "194.254.215.12" +network = "192.168.3.0" + +slicename = "inria_nepi" + +pl_user = os.environ.get("PL_USER") +pl_password = os.environ.get("PL_PASS") + +s1_node = add_node(ec, switch1, slicename, pl_user, pl_password) +s2_node = add_node(ec, switch2, slicename, pl_user, pl_password) + +# Add switches +ovs1 = add_ovs(ec, "nepi_bridge_1", "192.168.3.1/24", ip_controller, "6633", s1_node) +ovs2 = add_ovs(ec, "nepi_bridge_2", "192.168.3.2/24", ip_controller, "6633", s2_node) + +# Add ports on ovs +port1 = add_port(ec, "nepi_port1", ovs1) +port3 = add_port(ec, "nepi_port3", ovs1) +port2 = add_port(ec, "nepi_port2", ovs2) +port4 = add_port(ec, "nepi_port4", ovs2) + +h1_node = add_node(ec, host1, slicename, pl_user, pl_password) +h2_node = add_node(ec, host2, slicename, pl_user, pl_password) + +# Add tap devices +tap1 = add_tap(ec, "192.168.3.3", 24, "192.168.3.1", h1_node) +tap2 = add_tap(ec, "192.168.3.4", 24, "192.168.3.2", h2_node) + +# Connect the nodes +tunnel1 = add_tunnel(ec, network, port1, tap1) +tunnel2 = add_tunnel(ec, network, port2, tap2) +tunnel3 = add_tunnel(ec, network, port3, port4) + +# Add ping commands +app1 = add_app(ec, "ping -c5 192.168.3.2", s1_node) +app2 = add_app(ec, "ping -c5 192.168.3.3", s1_node) +app3 = add_app(ec, "ping -c5 192.168.3.4", s1_node) +app4 = add_app(ec, "ping -c5 192.168.3.1", s2_node) +app5 = add_app(ec, "ping -c5 192.168.3.3", s2_node) +app6 = add_app(ec, "ping -c5 192.168.3.4", s2_node) +app7 = add_app(ec, "ping -c5 192.168.3.1", h1_node) +app8 = add_app(ec, "ping -c5 192.168.3.2", h1_node) +app9 = add_app(ec, "ping -c5 192.168.3.4", h1_node) +app10 = add_app(ec, "ping -c5 192.168.3.1", h2_node) +app11 = add_app(ec, "ping -c5 192.168.3.2", h2_node) +app12 = add_app(ec, "ping -c5 192.168.3.3", h2_node) + +ec.deploy() + +ec.wait_finished([app1, app2, app3, app4, app5, app6, app7, app8, app9, app10, app11, app12]) + +# Retreive ping results and save +# them in a file +ping1 = ec.trace(app1, 'stdout') +ping2 = ec.trace(app2, 'stdout') +ping3 = ec.trace(app3, 'stdout') +ping4 = ec.trace(app4, 'stdout') +ping5 = ec.trace(app5, 'stdout') +ping6 = ec.trace(app6, 'stdout') +ping7 = ec.trace(app7, 'stdout') +ping8 = ec.trace(app8, 'stdout') +ping9 = ec.trace(app9, 'stdout') +ping10 = ec.trace(app10, 'stdout') +ping11 = ec.trace(app11, 'stdout') +ping12 = ec.trace(app12, 'stdout') + +if not ping12: + ec.shutdown() + sys.exit("No ping found") + +f = open("examples/openvswitch/ovs_ping_2switches.txt", 'w') +f.write("************ Ping From Switch 1 : 192.168.3.1 ********************\n\n") +f.write(ping1) +f.write("----------------------------------------\n\n") +f.write(ping2) +f.write("----------------------------------------\n\n") +f.write(ping3) +f.write("************ Ping From Switch 2 : 192.168.3.2 ********************\n\n") +f.write(ping4) +f.write("----------------------------------------\n\n") +f.write(ping5) +f.write("----------------------------------------\n\n") +f.write(ping6) +f.write("************ Ping From Host 1 : 192.168.3.3 ********************\n\n") +f.write(ping7) +f.write("----------------------------------------\n\n") +f.write(ping8) +f.write("----------------------------------------\n\n") +f.write(ping9) +f.write("************ Ping From Host 2 : 192.168.3.4 ********************\n\n") +f.write(ping10) +f.write("----------------------------------------\n\n") +f.write(ping11) +f.write("----------------------------------------\n\n") +f.write(ping12) + +f.close() + +# Delete the overlay network +ec.shutdown() + + + + + diff --git a/examples/openvswitch/ovs_ping_3switches_line.py b/examples/openvswitch/ovs_ping_3switches_line.py new file mode 100644 index 00000000..ca1ebeed --- /dev/null +++ b/examples/openvswitch/ovs_ping_3switches_line.py @@ -0,0 +1,212 @@ +#!/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 as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# 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 + + + +from nepi.execution.ec import ExperimentController +import os, time + +def add_node(ec, host, user, pl_user, pl_password): + node = ec.register_resource("PlanetlabNode") + ec.set(node, "hostname", host) + ec.set(node, "username", user) + if pl_user: + ec.set(node, "pluser", pl_user) + if pl_password: + ec.set(node, "plpassword", pl_password) + ec.set(node, "cleanHome", 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("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, ovs): + port = ec.register_resource("OVSPort") + ec.set(port, "port_name", port_name) + ec.register_connection(port, ovs) + return port + +def add_tap(ec, ip4, prefix4, pointopoint, node): + tap = ec.register_resource("PlanetlabTap") + ec.set(tap, "ip4", ip4) + ec.set(tap, "prefix4", prefix4) + ec.set(tap, "pointopoint", pointopoint) + ec.set(tap, "up", True) + ec.register_connection(tap, node) + return tap + +def add_tunnel(ec, network, port0, tap): + tunnel = ec.register_resource("OVSTunnel") + ec.set(tunnel, "network", network) + ec.register_connection(port0, tunnel) + ec.register_connection(tunnel, tap) + return tunnel + +def add_app(ec, command, node): + app = ec.register_resource("LinuxApplication") + ec.set(app, "command", command) + ec.register_connection(app, node) + return app + +# Create the EC +ec = ExperimentController(exp_id = "test-tr") + +switch1 = "planetlab2.virtues.fi" +switch2 = "planetlab2.upc.es" +switch3 = "planetlab2.cs.aueb.gr" +host1 = "planetlab2.ionio.gr" +host2 = "iraplab2.iralab.uni-karlsruhe.de" +host3 = "planetlab2.diku.dk" + +ip_controller = "194.254.215.12" +network = "192.168.3.0" + +slicename = "inria_nepi" + +pl_user = os.environ.get("PL_USER") +pl_password = os.environ.get("PL_PASS") + +s1_node = add_node(ec, switch1, slicename, pl_user, pl_password) +s2_node = add_node(ec, switch2, slicename, pl_user, pl_password) +s3_node = add_node(ec, switch3, slicename, pl_user, pl_password) + +# Add switches +ovs1 = add_ovs(ec, "nepi_bridge_1", "192.168.3.2/24", ip_controller, "6633", s1_node) +ovs2 = add_ovs(ec, "nepi_bridge_2", "192.168.3.4/24", ip_controller, "6633", s2_node) +ovs3 = add_ovs(ec, "nepi_bridge_3", "192.168.3.6/24", ip_controller, "6633", s3_node) + +# Add ports on ovs +port1 = add_port(ec, "nepi_port1", ovs1) +port4 = add_port(ec, "nepi_port4", ovs1) +port7 = add_port(ec, "nepi_port7", ovs1) +port2 = add_port(ec, "nepi_port2", ovs2) +port5 = add_port(ec, "nepi_port5", ovs2) +#port8 = add_port(ec, "nepi_port8", ovs2) +port3 = add_port(ec, "nepi_port3", ovs3) +port6 = add_port(ec, "nepi_port6", ovs3) +#port9 = add_port(ec, "nepi_port9", ovs3) + +h1_node = add_node(ec, host1, slicename, pl_user, pl_password) +h2_node = add_node(ec, host2, slicename, pl_user, pl_password) +h3_node = add_node(ec, host3, slicename, pl_user, pl_password) + +# Add tap devices +tap1 = add_tap(ec, "192.168.3.1", 24, "192.168.3.2", h1_node) +tap2 = add_tap(ec, "192.168.3.3", 24, "192.168.3.4", h2_node) +tap3 = add_tap(ec, "192.168.3.5", 24, "192.168.3.6", h3_node) + +# Connect the nodes +tunnel1 = add_tunnel(ec, network, port1, tap1) +tunnel2 = add_tunnel(ec, network, port2, tap2) +tunnel3 = add_tunnel(ec, network, port3, tap3) +tunnel4 = add_tunnel(ec, network, port4, port5) +tunnel5 = add_tunnel(ec, network, port7, port6) +#tunnel6 = add_tunnel(ec, network, port8, port9) + +# Add ping commands +app1 = add_app(ec, "ping -c5 192.168.3.4", s1_node) +app2 = add_app(ec, "ping -c5 192.168.3.6", s1_node) +app3 = add_app(ec, "ping -c5 192.168.3.2", s2_node) +app4 = add_app(ec, "ping -c5 192.168.3.6", s2_node) +app5 = add_app(ec, "ping -c5 192.168.3.2", s3_node) +app6 = add_app(ec, "ping -c5 192.168.3.4", s3_node) + +app7 = add_app(ec, "ping -c5 192.168.3.3", h1_node) +app8 = add_app(ec, "ping -c5 192.168.3.5", h1_node) +app9 = add_app(ec, "ping -c5 192.168.3.1", h2_node) +app10 = add_app(ec, "ping -c5 192.168.3.5", h2_node) +app11 = add_app(ec, "ping -c5 192.168.3.1", h3_node) +app12 = add_app(ec, "ping -c5 192.168.3.3", h3_node) + +ec.deploy() + +ec.wait_finished([app1, app2, app3, app4, app5, app6, app7, app8, app9, app10, app11, app12]) + +# Retreive ping results and save +# them in a file +ping1 = ec.trace(app1, 'stdout') +ping2 = ec.trace(app2, 'stdout') +ping3 = ec.trace(app3, 'stdout') +ping4 = ec.trace(app4, 'stdout') +ping5 = ec.trace(app5, 'stdout') +ping6 = ec.trace(app6, 'stdout') +ping7 = ec.trace(app7, 'stdout') +ping8 = ec.trace(app8, 'stdout') +ping9 = ec.trace(app9, 'stdout') +ping10 = ec.trace(app10, 'stdout') +ping11 = ec.trace(app11, 'stdout') +ping12 = ec.trace(app12, 'stdout') + + +f = open("examples/openvswitch/ovs_ping_3switches_line.txt", 'w') + +if not ping12: + ec.shutdown() + +f.write("************ Ping From Switch 1 : 192.168.3.2 ********************\n\n") +f.write(ping1) +f.write("--------------------------------------\n") +f.write(ping2) +f.write("************ Ping From Switch 2 : 192.168.3.4 ********************\n\n") +f.write(ping3) +f.write("--------------------------------------\n") +f.write(ping4) +f.write("************ Ping From Switch 3 : 192.168.3.6 ********************\n\n") +f.write(ping5) +f.write("--------------------------------------\n") +f.write(ping6) +f.write("************ Ping From Host 1 : 192.168.3.1 ********************\n\n") +f.write(ping7) +f.write("--------------------------------------\n") +f.write(ping8) +f.write("************ Ping From Host 2 : 192.168.3.3 ********************\n\n") +f.write(ping9) +f.write("--------------------------------------\n") +f.write(ping10) +f.write("************ Ping From Host 3 : 192.168.3.5 ********************\n\n") +f.write(ping11) +f.write("--------------------------------------\n") +f.write(ping12) +f.close() + +# Delete the overlay network +ec.shutdown() + + + + + diff --git a/examples/openvswitch/ovs_ping_3switches_loop.py b/examples/openvswitch/ovs_ping_3switches_loop.py new file mode 100644 index 00000000..54b2083d --- /dev/null +++ b/examples/openvswitch/ovs_ping_3switches_loop.py @@ -0,0 +1,221 @@ +#!/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 as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# 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 : +# +# Host3 +# | +# | +# | +# Switch3 +# / \ +# / \ +# / \ +# / \ +# Switch1 ----- Switch2 +# / \ +# / \ +# / \ +# Host1 Host2 + + + +from nepi.execution.ec import ExperimentController +import os, time + +def add_node(ec, host, user, pl_user, pl_password): + node = ec.register_resource("PlanetlabNode") + ec.set(node, "hostname", host) + ec.set(node, "username", user) + if pl_user: + ec.set(node, "pluser", pl_user) + if pl_password: + ec.set(node, "plpassword", pl_password) + ec.set(node, "cleanHome", 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("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, ovs): + port = ec.register_resource("OVSPort") + ec.set(port, "port_name", port_name) + ec.register_connection(port, ovs) + return port + +def add_tap(ec, ip4, prefix4, pointopoint, node): + tap = ec.register_resource("PlanetlabTap") + ec.set(tap, "ip4", ip4) + ec.set(tap, "prefix4", prefix4) + ec.set(tap, "pointopoint", pointopoint) + ec.set(tap, "up", True) + ec.register_connection(tap, node) + return tap + +def add_tunnel(ec, network, port0, tap): + tunnel = ec.register_resource("OVSTunnel") + ec.set(tunnel, "network", network) + ec.register_connection(port0, tunnel) + ec.register_connection(tunnel, tap) + return tunnel + +def add_app(ec, command, node): + app = ec.register_resource("LinuxApplication") + ec.set(app, "command", command) + ec.register_connection(app, node) + return app + +# Create the EC +ec = ExperimentController(exp_id = "test-tr") + +switch1 = "planetlab2.virtues.fi" +switch2 = "planetlab2.upc.es" +switch3 = "planetlab2.cs.aueb.gr" +host1 = "planetlab2.ionio.gr" +host2 = "iraplab2.iralab.uni-karlsruhe.de" +host3 = "planetlab2.diku.dk" + +ip_controller = "194.254.215.12" +network = "192.168.3.0" + +slicename = "inria_nepi" + +pl_user = os.environ.get("PL_USER") +pl_password = os.environ.get("PL_PASS") + +s1_node = add_node(ec, switch1, slicename, pl_user, pl_password) +s2_node = add_node(ec, switch2, slicename, pl_user, pl_password) +s3_node = add_node(ec, switch3, slicename, pl_user, pl_password) + +# Add switches +ovs1 = add_ovs(ec, "nepi_bridge_1", "192.168.3.2/24", ip_controller, "6633", s1_node) +ovs2 = add_ovs(ec, "nepi_bridge_2", "192.168.3.4/24", ip_controller, "6633", s2_node) +ovs3 = add_ovs(ec, "nepi_bridge_3", "192.168.3.6/24", ip_controller, "6633", s3_node) + +# Add ports on ovs +port1 = add_port(ec, "nepi_port1", ovs1) +port4 = add_port(ec, "nepi_port4", ovs1) +port7 = add_port(ec, "nepi_port7", ovs1) +port2 = add_port(ec, "nepi_port2", ovs2) +port5 = add_port(ec, "nepi_port5", ovs2) +port8 = add_port(ec, "nepi_port8", ovs2) +port3 = add_port(ec, "nepi_port3", ovs3) +port6 = add_port(ec, "nepi_port6", ovs3) +port9 = add_port(ec, "nepi_port9", ovs3) + +h1_node = add_node(ec, host1, slicename, pl_user, pl_password) +h2_node = add_node(ec, host2, slicename, pl_user, pl_password) +h3_node = add_node(ec, host3, slicename, pl_user, pl_password) + +# Add tap devices +tap1 = add_tap(ec, "192.168.3.1", 24, "192.168.3.2", h1_node) +tap2 = add_tap(ec, "192.168.3.3", 24, "192.168.3.4", h2_node) +tap3 = add_tap(ec, "192.168.3.5", 24, "192.168.3.6", h3_node) + +# Connect the nodes +tunnel1 = add_tunnel(ec, network, port1, tap1) +tunnel2 = add_tunnel(ec, network, port2, tap2) +tunnel3 = add_tunnel(ec, network, port3, tap3) +tunnel4 = add_tunnel(ec, network, port4, port5) +tunnel5 = add_tunnel(ec, network, port7, port6) +tunnel6 = add_tunnel(ec, network, port8, port9) + +# Add ping commands +app1 = add_app(ec, "ping -c5 192.168.3.4", s1_node) +app2 = add_app(ec, "ping -c5 192.168.3.6", s1_node) +app3 = add_app(ec, "ping -c5 192.168.3.2", s2_node) +app4 = add_app(ec, "ping -c5 192.168.3.6", s2_node) +app5 = add_app(ec, "ping -c5 192.168.3.2", s3_node) +app6 = add_app(ec, "ping -c5 192.168.3.4", s3_node) + +app7 = add_app(ec, "ping -c5 192.168.3.3", h1_node) +app8 = add_app(ec, "ping -c5 192.168.3.5", h1_node) +app9 = add_app(ec, "ping -c5 192.168.3.1", h2_node) +app10 = add_app(ec, "ping -c5 192.168.3.5", h2_node) +app11 = add_app(ec, "ping -c5 192.168.3.1", h3_node) +app12 = add_app(ec, "ping -c5 192.168.3.3", h3_node) + +ec.deploy() + +ec.wait_finished([app1, app2, app3, app4, app5, app6, app7, app8, app9, app10, app11, app12]) + +# Retreive ping results and save +# them in a file +ping1 = ec.trace(app1, 'stdout') +ping2 = ec.trace(app2, 'stdout') +ping3 = ec.trace(app3, 'stdout') +ping4 = ec.trace(app4, 'stdout') +ping5 = ec.trace(app5, 'stdout') +ping6 = ec.trace(app6, 'stdout') +ping7 = ec.trace(app7, 'stdout') +ping8 = ec.trace(app8, 'stdout') +ping9 = ec.trace(app9, 'stdout') +ping10 = ec.trace(app10, 'stdout') +ping11 = ec.trace(app11, 'stdout') +ping12 = ec.trace(app12, 'stdout') + + +f = open("examples/openvswitch/ovs_ping_3switches_loop.txt", 'w') + +if not ping12: + ec.shutdown() + +f.write("************ Ping From Switch 1 : 192.168.3.2 ********************\n\n") +f.write(ping1) +f.write("--------------------------------------\n") +f.write(ping2) +f.write("************ Ping From Switch 2 : 192.168.3.4 ********************\n\n") +f.write(ping3) +f.write("--------------------------------------\n") +f.write(ping4) +f.write("************ Ping From Switch 3 : 192.168.3.6 ********************\n\n") +f.write(ping5) +f.write("--------------------------------------\n") +f.write(ping6) +f.write("************ Ping From Host 1 : 192.168.3.1 ********************\n\n") +f.write(ping7) +f.write("--------------------------------------\n") +f.write(ping8) +f.write("************ Ping From Host 2 : 192.168.3.3 ********************\n\n") +f.write(ping9) +f.write("--------------------------------------\n") +f.write(ping10) +f.write("************ Ping From Host 3 : 192.168.3.5 ********************\n\n") +f.write(ping11) +f.write("--------------------------------------\n") +f.write(ping12) +f.close() + +# Delete the overlay network +ec.shutdown() + + + + + diff --git a/examples/openvswitch/ping_over_udpTapTunnel_performance_test_triangleTopo.py b/examples/openvswitch/ping_over_udpTapTunnel_performance_test_triangleTopo.py new file mode 100644 index 00000000..e85da451 --- /dev/null +++ b/examples/openvswitch/ping_over_udpTapTunnel_performance_test_triangleTopo.py @@ -0,0 +1,228 @@ +#!/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 as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# 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 : +# +# Host3 +# | +# | +# | +# Switch3 +# / \ +# / \ +# / \ +# / \ +# Switch1 ----- Switch2 +# / \ +# / \ +# / \ +# Host1 Host2 + +from nepi.execution.ec import ExperimentController + +import os +import time + +### Useful Method to Create RM ## +def add_node(ec, host, user): + node = ec.register_resource("PlanetlabNode") + ec.set(node, "hostname", host) + ec.set(node, "username", user) + ec.set(node, "cleanHome", True) + ec.set(node, "cleanProcesses", True) + return node + +def add_tap(ec, ip4, prefix4, pointopoint, node): + tap = ec.register_resource("PlanetlabTap") + ec.set(tap, "ip4", ip4) + ec.set(tap, "prefix4", prefix4) + ec.set(tap, "pointopoint", pointopoint) + ec.set(tap, "up", True) + ec.register_connection(tap, node) + return tap + +def add_udptun(ec, tap1, tap2): + udptun = ec.register_resource("UdpTunnel") + ec.register_connection(tap1, udptun) + ec.register_connection(tap2, udptun) + return udptun + +def add_vroute(ec, network, tap): + vroute = ec.register_resource("PlanetlabVroute") + ec.set(vroute, "action", "add") + ec.set(vroute, "network", network) + ec.register_connection(vroute, tap) + return vroute + +def add_app(ec, command, node): + app = ec.register_resource("LinuxApplication") + ec.set(app, "command", command) + ec.register_connection(app, node) + return app + +### Data that can be changed ### +user = "inria_nepi" + +hostname_switch1 = "planetlab2.virtues.fi" +hostname_switch2 = "planetlab2.upc.es" +hostname_switch3 = "planetlab2.cs.aueb.gr" +hostname_host1 = "planetlab2.ionio.gr" +hostname_host2 = "iraplab2.iralab.uni-karlsruhe.de" +hostname_host3 = "planetlab2.diku.dk" + + +### Start Experiment ### +ec = ExperimentController(exp_id = "test-tap-tunnel") + +## Create The topology ## +host1 = add_node(ec, hostname_host1, user) +tap1 = add_tap(ec, "192.168.3.1", 24, "192.168.3.2", host1) + +switch1 = add_node(ec, hostname_switch1, user) +tap2 = add_tap(ec, "192.168.3.2", 24, "192.168.3.1", switch1) +tap102 = add_tap(ec, "192.168.3.102", 29, "192.168.3.104", switch1) +tap152 = add_tap(ec, "192.168.3.152", 29, "192.168.3.156", switch1) + +host2 = add_node(ec, hostname_host2, user) +tap13 = add_tap(ec, "192.168.3.13", 24, "192.168.3.14", host2) + +switch2 = add_node(ec, hostname_switch2, user) +tap14 = add_tap(ec, "192.168.3.14", 24, "192.168.3.13", switch2) +tap104 = add_tap(ec, "192.168.3.104", 29, "192.168.3.102", switch2) +tap204 = add_tap(ec, "192.168.3.204", 29, "192.168.3.206", switch2) + +host3 = add_node(ec, hostname_host3, user) +tap25 = add_tap(ec, "192.168.3.25", 24, "192.168.3.26", host3) + +switch3 = add_node(ec, hostname_switch3, user) +tap26 = add_tap(ec, "192.168.3.26", 24, "192.168.3.25", switch3) +tap156 = add_tap(ec, "192.168.3.156", 29, "192.168.3.152", switch3) +tap206 = add_tap(ec, "192.168.3.206", 29, "192.168.3.204", switch3) + +## Create the UDP Tunnel ## +udptun1 = add_udptun(ec, tap1, tap2) +udptun2 = add_udptun(ec, tap13, tap14) +udptun3 = add_udptun(ec, tap25, tap26) + +udptun4 = add_udptun(ec, tap102, tap104) +udptun5 = add_udptun(ec, tap152, tap156) +udptun6 = add_udptun(ec, tap204, tap206) + +## Create the PlanetLab Route ## +vroute1 = add_vroute(ec, "192.168.3.0", tap1) +vroute2 = add_vroute(ec, "192.168.3.0", tap13) +vroute3 = add_vroute(ec, "192.168.3.0", tap25) + +vroute7 = add_vroute(ec, "192.168.3.8", tap102) +vroute8 = add_vroute(ec, "192.168.3.0", tap104) +vroute9 = add_vroute(ec, "192.168.3.24", tap152) +vroute10 = add_vroute(ec, "192.168.3.0", tap156) +vroute11 = add_vroute(ec, "192.168.3.24", tap204) +vroute12 = add_vroute(ec, "192.168.3.8", tap206) + +## Create all the Ping ## + +app1 = add_app(ec, "ping -c8 192.168.3.13", host1) +app2 = add_app(ec, "ping -c8 192.168.3.25", host1) +app3 = add_app(ec, "ping -c8 192.168.3.104", host1) +app4 = add_app(ec, "ping -c8 192.168.3.156", host1) +app5 = add_app(ec, "ping -c8 192.168.3.2", host1) + +app11 = add_app(ec, "ping -c8 192.168.3.1", host2) +app12 = add_app(ec, "ping -c8 192.168.3.25", host2) +app13 = add_app(ec, "ping -c8 192.168.3.102", host2) +app14 = add_app(ec, "ping -c8 192.168.3.206", host2) +app15 = add_app(ec, "ping -c8 192.168.3.14", host2) + +app21 = add_app(ec, "ping -c8 192.168.3.1", host3) +app22 = add_app(ec, "ping -c8 192.168.3.13", host3) +app23 = add_app(ec, "ping -c8 192.168.3.152", host3) +app24 = add_app(ec, "ping -c8 192.168.3.204", host3) +app25 = add_app(ec, "ping -c8 192.168.3.26", host3) + +ec.deploy() + +ec.wait_finished([app1 ,app2, app3, app4, app5, app11 ,app12, app13, app14, app15, app21 ,app22, app23, app24, app25]) + +# Retreive ping results and save +# them in a file +ping1 = ec.trace(app1, 'stdout') +ping2 = ec.trace(app2, 'stdout') +ping3 = ec.trace(app3, 'stdout') +ping4 = ec.trace(app4, 'stdout') +ping5 = ec.trace(app5, 'stdout') +ping11 = ec.trace(app11, 'stdout') +ping12 = ec.trace(app12, 'stdout') +ping13 = ec.trace(app13, 'stdout') +ping14 = ec.trace(app14, 'stdout') +ping15 = ec.trace(app15, 'stdout') +ping21 = ec.trace(app21, 'stdout') +ping22 = ec.trace(app22, 'stdout') +ping23 = ec.trace(app23, 'stdout') +ping24 = ec.trace(app24, 'stdout') +ping25 = ec.trace(app25, 'stdout') + +f = open("examples/openvswitch/ping_over_udpTapTunnel_performance_test.txt", 'w') + +if not ping25: + ec.shutdown() + + +f.write("************ Ping From Host 1 : 192.168.3.1 ********************\n\n") +f.write(ping1) +f.write("----------------------------------------\n\n") +f.write(ping2) +f.write("----------------------------------------\n\n") +f.write(ping3) +f.write("----------------------------------------\n\n") +f.write(ping4) +f.write("----------------------------------------\n\n") +f.write(ping5) +f.write("************ Ping From Host 2 : 192.168.3.13 ********************\n\n") +f.write(ping11) +f.write("----------------------------------------\n\n") +f.write(ping12) +f.write("----------------------------------------\n\n") +f.write(ping13) +f.write("----------------------------------------\n\n") +f.write(ping14) +f.write("----------------------------------------\n\n") +f.write(ping15) +f.write("************ Ping From Host 3 : 192.168.3.25 ********************\n\n") +f.write(ping21) +f.write("----------------------------------------\n\n") +f.write(ping22) +f.write("----------------------------------------\n\n") +f.write(ping23) +f.write("----------------------------------------\n\n") +f.write(ping24) +f.write("----------------------------------------\n\n") +f.write(ping25) + +f.close() + +# Delete the overlay network +ec.shutdown() + + + + + diff --git a/src/nepi/resources/linux/udptunnel.py b/src/nepi/resources/linux/udptunnel.py index ba96788f..29089fd0 100644 --- a/src/nepi/resources/linux/udptunnel.py +++ b/src/nepi/resources/linux/udptunnel.py @@ -289,7 +289,7 @@ class UdpTunnel(LinuxApplication): result = None delay = 1.0 - for i in xrange(4): + for i in xrange(20): (out, err), proc = endpoint.node.check_output( self.run_home(endpoint), filename) diff --git a/src/nepi/resources/planetlab/openvswitch/ovs.py b/src/nepi/resources/planetlab/openvswitch/ovs.py index f4b50c6c..39567b3f 100644 --- a/src/nepi/resources/planetlab/openvswitch/ovs.py +++ b/src/nepi/resources/planetlab/openvswitch/ovs.py @@ -29,9 +29,18 @@ import os reschedule_delay = "0.5s" @clsinit_copy -class OVSWitch(LinuxApplication): - - _rtype = "OVSWitch" +class OVSSwitch(LinuxApplication): + """ + .. class:: Class Args : + + :param ec: The Experiment controller + :type ec: ExperimentController + :param guid: guid of the RM + :type guid: int + + """ + + _rtype = "OVSSwitch" _help = "Runs an OpenVSwitch on a PlanetLab host" _backend = "planetlab" @@ -39,7 +48,7 @@ class OVSWitch(LinuxApplication): @classmethod def _register_attributes(cls): - """ Register the attributes of OVSWitch RM + """ Register the attributes of OVSSwitch RM """ bridge_name = Attribute("bridge_name", "Name of the switch/bridge", @@ -64,18 +73,21 @@ class OVSWitch(LinuxApplication): :type guid: int """ - super(OVSWitch, self).__init__(ec, guid) - self._pid = None - self._ppid = None - self._home = "ovswitch-%s" % self.guid + super(OVSSwitch, self).__init__(ec, guid) + self._home = "ovsswitch-%s" % self.guid self._checks = "ovsChecks-%s" % self.guid @property def node(self): + """ Node wthat run the switch + """ node = self.get_connected(PlanetlabNode.get_rtype()) if node: return node[0] return None + def log_message(self, msg): + return " guid %d - OVSSwitch - %s " % (self.guid, msg) + @property def ovs_home(self): return os.path.join(self.node.exp_home, self._home) @@ -84,49 +96,60 @@ class OVSWitch(LinuxApplication): def ovs_checks(self): return os.path.join(self.ovs_home, self._checks) - @property - def pid(self): - return self._pid + def valid_connection(self, guid): + """ Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed. - @property - def ppid(self): - return self._ppid - -# 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 + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean - def valid_connection(self, guid): - # TODO: Validate! - return True + """ + 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 do_provision(self): + """ Create the different OVS folder. + """ + # create home dir for ovs self.node.mkdir(self.ovs_home) # create dir for ovs checks self.node.mkdir(self.ovs_checks) - super(OVSWitch, self).do_provision() + super(OVSSwitch, self).do_provision() + + 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.ec.schedule(reschedule_delay, self.deploy) + return + + self.do_discover() + self.do_provision() + + self.check_sliver_ovs() + self.servers_on() + self.create_bridge() + self.assign_controller() + self.ovs_status() + + super(OVSSwitch, self).do_deploy() def check_sliver_ovs(self): - """ Check if sliver-ovs exists. If it does not exist, we interrupt - the execution immediately. + """ Check if sliver-ovs exists. If it does not exist, the execution is stopped """ + cmd = "compgen -c | grep sliver-ovs" out = err = "" @@ -146,34 +169,14 @@ class OVSWitch(LinuxApplication): raise RuntimeError, msg msg = "Command sliver-ovs exists" - self.debug(msg) - - 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(reschedule_delay, self.deploy) - return - - self.do_discover() - self.do_provision() - self.check_sliver_ovs() - self.servers_on() - self.create_bridge() - self.assign_controller() - self.ovs_status() - - super(OVSWitch, self).do_deploy() + self.debug(msg) def servers_on(self): - """ Start the openvswitch servers and also checking - if they started successfully + """ Start the openvswitch servers and check it """ - self.info("Starting the OVSWitch servers") - command = ("sliver-ovs start") - + + # Start the server + command = "sliver-ovs start" out = err = "" (out, err), proc = self.node.run_and_wait(command, self.ovs_checks, shfile = "start_srv.sh", @@ -183,13 +186,13 @@ class OVSWitch(LinuxApplication): raise_on_error = True, stdout = "start_srv_stdout", stderr = "start_srv_stderr") - (out, err), proc = self.node.check_output(self.ovs_checks, 'start_srv_exitcode') if out != "0\n": self.error("Servers have not started") raise RuntimeError, msg + # Check if the servers are running or not cmd = "ps -A | grep ovsdb-server" out = err = "" (out, err), proc = self.node.run_and_wait(cmd, self.ovs_checks, @@ -199,42 +202,29 @@ class OVSWitch(LinuxApplication): sudo = True, stdout = "status_srv_stdout", stderr = "status_srv_stderr") - - # Check if the servers are running or not (out, err), proc = self.node.check_output(self.ovs_checks, 'status_srv_exitcode') if out != "0\n": - self.error("Servers are not running") + msg = "Servers are not running" + self.error(msg) raise RuntimeError, msg - self.info("Servers started") - - def del_old_br(self): - # TODO: Delete old bridges that might exist maybe by adding atribute - """ With ovs-vsctl list-br - """ - pass + self.info("Server OVS Started Correctly") def create_bridge(self): - """ Create the bridge/switch and we check if we have any - error during the SSH connection + """ 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 - self.del_old_br() + if not (self.get("bridge_name") and self.get("virtual_ip_pref")): msg = "No assignment in one or both attributes" self.error(msg) - self.debug("Bridge name is %s and virtual_ip_pref is %s" %\ - (self.get("bridge_name"), self.get("virtual_ip_pref")) ) raise AttributeError, msg - - bridge_name = self.get("bridge_name") - virtual_ip_pref = self.get("virtual_ip_pref") - self.info(" Creating the bridge %s and assigning %s" %\ - (bridge_name, virtual_ip_pref) ) + cmd = "sliver-ovs create-bridge '%s' '%s'" %\ - (bridge_name, virtual_ip_pref) + (self.get("bridge_name"), self.get("virtual_ip_pref")) out = err = "" (out, err), proc = self.node.run_and_wait(cmd, self.ovs_checks, shfile = "create_br.sh", @@ -243,38 +233,45 @@ class OVSWitch(LinuxApplication): sudo = True, stdout = "create_br_stdout", stderr = "create_br_stderr") - (out, err), proc = self.node.check_output(self.ovs_checks, 'create_br_exitcode') + if out != "0\n": msg = "No such pltap netdev\novs-appctl: ovs-vswitchd: server returned an error" - self.debug("Check again the virtual IP") + self.error(msg) raise RuntimeError, msg - self.info("Bridge %s created" % bridge_name) + self.info(" Bridge %s Created and Assigned to %s" %\ + (self.get("bridge_name"), self.get("virtual_ip_pref")) ) def assign_controller(self): """ Set the controller IP """ - if self.get("controller_ip") and self.get("controller_port"): - controller_ip = self.get("controller_ip") - controller_port = self.get("controller_port") - self.info("Assigning the controller to the %s" % self.get("bridge_name")) - cmd = "ovs-vsctl set-controller %s tcp:%s:%s" %\ - (self.get("bridge_name"), controller_ip, controller_port) - out = err = "" - (out, err), proc = self.node.run(cmd, self.ovs_checks, - sudo = True, - stdout = "stdout", - stderr = "stderr") - if err != "": - self.debug("SSH connection refusing in assign_contr") - raise RuntimeError, msg - self.info("Controller assigned") + + 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 + + cmd = "ovs-vsctl set-controller %s tcp:%s:%s" %\ + (self.get("bridge_name"), self.get("controller_ip"), self.get("controller_port")) + out = err = "" + (out, err), proc = self.node.run(cmd, self.ovs_checks, + sudo = True, + stdout = "stdout", + stderr = "stderr") + + if err != "": + msg = "SSH connection in the method assign_controller" + self.error(msg) + raise RuntimeError, msg + + self.info("Controller assigned to the bridge %s" % self.get("bridge_name")) def ovs_status(self): - """ Print the status of the created bridge + """ Print the status of the bridge """ + cmd = "sliver-ovs show | tail -n +2" out = err = "" (out, err), proc = self.node.run_and_wait(cmd, self.ovs_home, @@ -282,33 +279,43 @@ class OVSWitch(LinuxApplication): stdout = "show_stdout", stderr = "show_stderr") (out, err), proc = self.node.check_output(self.ovs_home, 'show_stdout') - self.info(out) + + if out == "": + msg = "Error when checking the status of the OpenVswitch" + self.error(msg) + raise RuntimeError, msg + + self.debug(out) def do_release(self): - """ Delete the bridge and - close the servers + """ 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 + """ - # Node needs to wait until all associated RMs are released - # to be released + from nepi.resources.planetlab.openvswitch.ovsport import OVSPort rm = self.get_connected(OVSPort.get_rtype()) - if rm[0].state < ResourceState.STOPPED: + if rm[0].state < ResourceState.RELEASED: self.ec.schedule(reschedule_delay, self.release) return - msg = "Deleting the bridge %s" % self.get('bridge_name') - self.info(msg) cmd = "sliver-ovs del-bridge %s" % self.get('bridge_name') (out, err), proc = self.node.run(cmd, self.ovs_checks, sudo = True) + cmd = "sliver-ovs stop" (out, err), proc = self.node.run(cmd, self.ovs_checks, sudo = True) + + msg = "Deleting the bridge %s" % self.get('bridge_name') + self.info(msg) if proc.poll(): self.error(msg, out, err) raise RuntimeError, msg - super(OVSWitch, self).do_release() + super(OVSSwitch, self).do_release() diff --git a/src/nepi/resources/planetlab/openvswitch/ovsport.py b/src/nepi/resources/planetlab/openvswitch/ovsport.py index cd2e848d..481fe05f 100644 --- a/src/nepi/resources/planetlab/openvswitch/ovsport.py +++ b/src/nepi/resources/planetlab/openvswitch/ovsport.py @@ -21,7 +21,7 @@ from nepi.execution.attribute import Attribute, Flags, Types from nepi.execution.resource import ResourceManager, clsinit_copy, \ ResourceState -from nepi.resources.planetlab.openvswitch.ovs import OVSWitch +from nepi.resources.planetlab.openvswitch.ovs import OVSSwitch from nepi.resources.planetlab.node import PlanetlabNode from nepi.resources.linux.application import LinuxApplication @@ -43,7 +43,7 @@ class OVSPort(LinuxApplication): _help = "Runs an OpenVSwitch on a PlanetLab host" _backend = "planetlab" - _authorized_connections = ["OVSWitch", "Tunnel"] + _authorized_connections = ["OVSSwitch", "OVSTunnel"] @classmethod def _register_attributes(cls): @@ -67,9 +67,14 @@ class OVSPort(LinuxApplication): self._port_number = None self.port_info = [] + def log_message(self, msg): + return " guid %d - OVSPort - %s " % (self.guid, msg) + @property def node(self): - rm_list = self.get_connected(OVSWitch.get_rtype()) + """ Node that run the switch and the ports + """ + rm_list = self.get_connected(OVSSwitch.get_rtype()) if rm_list: for elt in rm_list: node = elt.get_connected(PlanetlabNode.get_rtype()) @@ -77,9 +82,11 @@ class OVSPort(LinuxApplication): return node[0] @property - def ovswitch(self): - ovswitch = self.get_connected(OVSWitch.get_rtype()) - if ovswitch: return ovswitch[0] + def ovsswitch(self): + """ Switch where the port is created + """ + ovsswitch = self.get_connected(OVSSwitch.get_rtype()) + if ovsswitch: return ovsswitch[0] return None @property @@ -87,70 +94,58 @@ class OVSPort(LinuxApplication): return self._port_number def valid_connection(self, guid): - # TODO: Validate! - return True - -# 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() 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) - - def get_host_ip(self): - """ Get the hostname of the node that - the port belongs to. We use it for tunnel. + """ Check if the connection is available. + + :param guid: Guid of the current RM + :type guid: int + :rtype: Boolean + """ - get_host_ip = self.node - if not get_host_ip: - msg = "info_list is empty" + 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) - raise RuntimeError, msg + return True + msg = "Connection between %s %s and %s %s refused" % (self.get_rtype(), self._guid, rm.get_rtype(), guid) + self.debug(msg) - import socket - self.port_info.append(get_host_ip.get('hostname')) - self.port_info.append(socket.gethostbyname(self.port_info[0])) - def create_port(self): """ Create the desired port """ - port_name = self.get('port_name') + msg = "Creating the port %s" % self.get('port_name') + self.debug(msg) - if not (port_name or self.ovswitch): - msg = "The rm_list is empty or the port name is not assigned\n Failed to create port" + if not self.get('port_name'): + msg = "The port name is not assigned" self.error(msg) - self.debug("ovswitch_list = %s and port_name = %s" % (self.ovswitch, port_name) ) raise AttributeError, msg - self.info("Create the port %s on switch %s" % (port_name, self.ovswitch.get('bridge_name'))) - self.port_info.append(port_name) - self.port_info.append(self.ovswitch.get('virtual_ip_pref')) - cmd = "sliver-ovs create-port %s %s" % (self.ovswitch.get('bridge_name'), port_name) - self.node.run(cmd, self.ovswitch.ovs_checks, - stderr = "stdout-%s" % port_name, - stdout = "stderr-%s" % port_name, + if not self.ovsswitch: + msg = "The OVSwitch RM is not running" + self.error(msg) + raise AttributeError, msg + + cmd = "sliver-ovs create-port %s %s" % (self.ovsswitch.get('bridge_name'), + self.get('port_name')) + self.node.run(cmd, self.ovsswitch.ovs_checks, + stderr = "stdout-%s" % self.get('port_name'), + stdout = "stderr-%s" % self.get('port_name'), sudo = True) + + self.info("Created the port %s on switch %s" % (self.get('port_name'), + self.ovsswitch.get('bridge_name'))) def get_local_end(self): """ Get the local_endpoint of the port """ - msg = "Discovering the number of the port %s"\ - % self.get('port_name') - self.info(msg) - command = "sliver-ovs get-local-endpoint %s"\ - % self.get('port_name') + msg = "Discovering the number of the port %s" % self.get('port_name') + self.debug(msg) + + command = "sliver-ovs get-local-endpoint %s" % self.get('port_name') out = err = "" - (out, err), proc = self.node.run_and_wait(command, self.ovswitch.ovs_checks, + (out, err), proc = self.node.run_and_wait(command, + self.ovsswitch.ovs_checks, shfile = "port_number-%s.sh" % self.get('port_name'), pidfile = "port_number_pidfile-%s" % self.get('port_name'), ecodefile = "port_number_exitcode-%s" % self.get('port_name'), @@ -159,20 +154,39 @@ class OVSPort(LinuxApplication): stderr = "stderr-%s" % self.get('port_name')) if err != "": - msg = "No assignment in attribute port_name" + msg = "Error retrieving the local endpoint of the port" self.error(msg) - self.debug("You are in the method get_local_end and the port_name = %s" % self.get('port_name')) raise AttributeError, msg - self._port_number = None - self._port_number = int(out) - self.port_info.append(self._port_number) - self.info("The number of the %s is %s" % (self.get('port_name'), self._port_number)) + if out: + self._port_number = int(out) + + self.info("The number of the %s is %s" % (self.get('port_name'), + self.port_number)) + def set_port_info(self): + """ Set all the information about the port inside a list + """ + + info = [] + info.append(self.node.get('hostname')) + + #Return the ip of the node + import socket + ip = socket.gethostbyname(self.node.get('hostname')) + info.append(ip) + + info.append(self.get('port_name')) + info.append(self.ovsswitch.get('virtual_ip_pref')) + info.append(self.port_number) + return info + def switch_connect_command(self, local_port_name, remote_ip, remote_port_num): - """ Script for switch links + """ Script to create the connection from a switch to a + remote endpoint """ + command = ["sliver-ovs"] command.append("set-remote-endpoint ") command.append("%s " % local_port_name) @@ -183,42 +197,47 @@ class OVSPort(LinuxApplication): return command def do_deploy(self): - """ Wait until ovswitch is started + """ Deploy the OVS port after the OVS Switch """ - ovswitch = self.ovswitch - if not ovswitch or ovswitch.state < ResourceState.READY: - self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.ovswitch.state ) + if not self.ovsswitch or self.ovsswitch.state < ResourceState.READY: + self.debug("---- RESCHEDULING DEPLOY ---- OVSwitch state %s " % self.ovsswitch.state ) self.ec.schedule(reschedule_delay, self.deploy) return self.do_discover() self.do_provision() - self.get_host_ip() + self.create_port() self.get_local_end() - self.ovswitch.ovs_status() + + #Check the status of the OVS Switch + self.ovsswitch.ovs_status() + + # Save all the information inside a list + self.port_info = self.set_port_info() super(OVSPort, self).do_deploy() def do_release(self): - """ Release the port RM means delete the ports + """ Delete the port on the OVSwitch. It needs to wait for the tunnel + to be released. """ - # OVS needs to wait until all associated RMs are released - # to be released + from nepi.resources.planetlab.openvswitch.tunnel import OVSTunnel rm = self.get_connected(OVSTunnel.get_rtype()) - if rm and rm[0].state < ResourceState.STOPPED: + if rm and rm[0].state < ResourceState.RELEASED: self.ec.schedule(reschedule_delay, self.release) return - msg = "Deleting the port %s" % self.get('port_name') - self.info(msg) cmd = "sliver-ovs del_port %s" % self.get('port_name') - (out, err), proc = self.node.run(cmd, self.ovswitch.ovs_checks, + (out, err), proc = self.node.run(cmd, self.ovsswitch.ovs_checks, sudo = True) + msg = "Deleting the port %s" % self.get('port_name') + self.info(msg) + if proc.poll(): self.error(msg, out, err) raise RuntimeError, msg diff --git a/src/nepi/resources/planetlab/openvswitch/tunnel.py b/src/nepi/resources/planetlab/openvswitch/tunnel.py index 57a889a4..a26f4415 100644 --- a/src/nepi/resources/planetlab/openvswitch/tunnel.py +++ b/src/nepi/resources/planetlab/openvswitch/tunnel.py @@ -24,7 +24,7 @@ from nepi.execution.resource import ResourceManager, ResourceFactory, clsinit_co ResourceState from nepi.resources.linux.application import LinuxApplication from nepi.resources.planetlab.node import PlanetlabNode -from nepi.resources.planetlab.openvswitch.ovs import OVSWitch +from nepi.resources.planetlab.openvswitch.ovs import OVSSwitch from nepi.util.timefuncs import tnow, tdiffsec from nepi.resources.planetlab.vroute import PlanetlabVroute from nepi.resources.planetlab.tap import PlanetlabTap @@ -54,7 +54,7 @@ class OVSTunnel(LinuxApplication): @classmethod def _register_attributes(cls): - """ Register the attributes of Connection RM + """ Register the attributes of OVSTunnel RM """ network = Attribute("network", "IPv4 Network Address", @@ -103,222 +103,118 @@ class OVSTunnel(LinuxApplication): super(OVSTunnel, self).__init__(ec, guid) self._home = "tunnel-%s" % self.guid self.port_info_tunl = [] - self._nodes = [] self._pid = None self._ppid = None self._vroute = None - + self._node_endpoint1 = None + self._node_endpoint2 = None def log_message(self, msg): return " guid %d - Tunnel - %s " % (self.guid, msg) - @property - def node(self): - if self._nodes: - return self._nodes[0] - def app_home(self, node): - return os.path.join(self.node.exp_home, self._home) + return os.path.join(node.exp_home, self._home) def run_home(self, node): return os.path.join(self.app_home(node), self.ec.run_id) - def port_endpoints(self): - # Switch-Switch connection - connected = [] + @property + def tap(self): + """ Return the Tap RM if it exists """ + rclass = ResourceFactory.get_resource_type(PlanetlabTap.get_rtype()) for guid in self.connections: rm = self.ec.get_resource(guid) - if hasattr(rm, "create_port"): - connected.append(rm) - return connected + if isinstance(rm, rclass): + return rm - - def mixed_endpoints(self): - # Switch-Host connection - connected = [1, 2] + @property + def ovsswitch(self): + """ Return the 1st switch """ + for guid in self.connections: + rm_port = self.ec.get_resource(guid) + if hasattr(rm_port, "create_port"): + rm_list = rm_port.get_connected(OVSSwitch.get_rtype()) + if rm_list: + return rm_list[0] + + @property + def check_switch_host_link(self): + """ Check if the links are between switches + or switch-host. Return False for the latter. + """ + if self.tap : + return True + return False + + + def endpoints(self): + """ Return the list with the two connected elements. + Either Switch-Switch or Switch-Host + """ + connected = [1, 1] + position = 0 for guid in self.connections: rm = self.ec.get_resource(guid) if hasattr(rm, "create_port"): - connected[0] = rm + connected[position] = rm + position += 1 elif hasattr(rm, "udp_connect_command"): connected[1] = rm return connected def get_node(self, endpoint): - # Get connected to the nodes - res = [] + """ Get the nodes of the endpoint + """ + rm = [] if hasattr(endpoint, "create_port"): - rm_list = endpoint.get_connected(OVSWitch.get_rtype()) + rm_list = endpoint.get_connected(OVSSwitch.get_rtype()) if rm_list: rm = rm_list[0].get_connected(PlanetlabNode.get_rtype()) else: rm = endpoint.get_connected(PlanetlabNode.get_rtype()) if rm : - res.append(rm[0]) - return res + return rm[0] @property def endpoint1(self): - if self.check_endpoints: - port_endpoints = self.port_endpoints() - if port_endpoints: return port_endpoints[0] - else: - mixed_endpoints = self.mixed_endpoints() - if mixed_endpoints: return mixed_endpoints[0] + """ Return the first endpoint : Always a Switch + """ + endpoint = self.endpoints() + return endpoint[0] @property def endpoint2(self): - if self.check_endpoints: - port_endpoints = self.port_endpoints() - if port_endpoints: return port_endpoints[1] - else: - mixed_endpoints = self.mixed_endpoints() - if mixed_endpoints: return mixed_endpoints[1] - - @property - def check_endpoints(self): - """ Check if the links are between switches - or switch-host. Return False for latter. + """ Return the second endpoint : Either a Switch or a TAP """ - port_endpoints = self.port_endpoints() - if len(port_endpoints) == 2: - return True - return False + endpoint = self.endpoints() + return endpoint[1] - def get_port_info(self, endpoint, rem_endpoint): + def get_port_info(self, endpoint1, endpoint2): + #TODO : Need to change it. Really bad to have method that return different type of things !!!!! """ Retrieve the port_info list for each port - :param port_info_tunl: [hostname, publ_IP_addr, port_name, - virtual_ip, local_port_Numb] - :type port_info_tunl: list - """ - self.port_info_tunl = [] - if self.check_endpoints: - # Use for the link switch-->switch - self.port_info_tunl.append(endpoint.port_info) - host0, ip0, pname0, virt_ip0, pnumber0 = self.port_info_tunl[0] - self.port_info_tunl.append(rem_endpoint.port_info) - host1, ip1, pname1, virt_ip1, pnumber1 = self.port_info_tunl[1] - return (pname0, ip1, pnumber1) - - # Use for the link host-->switch - self.port_info_tunl.append(endpoint.port_info) - host0, ip0, pname0, virt_ip0, pnumber0 = self.port_info_tunl[0] - return pnumber0 - - def udp_connect(self, endpoint, rem_endpoint): - # Collect info from rem_endpoint - self._nodes = self.get_node(rem_endpoint) - remote_ip = socket.gethostbyname(self.node.get("hostname")) - # Collect info from endpoint - self._nodes = self.get_node(endpoint) - local_port_file = os.path.join(self.run_home(self.node), - "local_port") - remote_port_file = os.path.join(self.run_home(self.node), - "remote_port") - ret_file = os.path.join(self.run_home(self.node), - "ret_file") - cipher = self.get("cipher") - cipher_key = self.get("cipherKey") - bwlimit = self.get("bwLimit") - txqueuelen = self.get("txQueueLen") - - rem_port = str(self.get_port_info(rem_endpoint, endpoint)) - # Upload the remote port in a file - self.node.upload(rem_port, - remote_port_file, - text = True, - overwrite = False) - - udp_connect_command = endpoint.udp_connect_command( - remote_ip, local_port_file, remote_port_file, - ret_file, cipher, cipher_key, bwlimit, txqueuelen) - - # upload command to host_connect.sh script - shfile = os.path.join(self.app_home(self.node), "host_connect.sh") - self.node.upload(udp_connect_command, - shfile, - text = True, - overwrite = False) - - # invoke connect script - cmd = "bash %s" % shfile - (out, err), proc = self.node.run(cmd, self.run_home(self.node), - sudo = True, - stdout = "udp_stdout", - stderr = "udp_stderr") - - # check if execution errors - msg = "Failed to connect endpoints" - - if proc.poll(): - self.error(msg, out, err) - raise RuntimeError, msg - - msg = "Connection on host %s configured" \ - % self.node.get("hostname") - self.debug(msg) - - # Wait for pid file to be generated - self._nodes = self.get_node(endpoint) - pid, ppid = self.node.wait_pid(self.run_home(self.node)) - - # 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(self.run_home(self.node)) - # 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 (pid, ppid) - - def switch_connect(self, endpoint, rem_endpoint): - """ Get switch connect command """ - # Get and configure switch connection command - (local_port_name, remote_ip, remote_port_num) = self.get_port_info( - endpoint, rem_endpoint) - switch_connect_command = endpoint.switch_connect_command( - local_port_name, remote_ip, remote_port_num) - self._nodes = self.get_node(endpoint) - - # Upload command to the file sw_connect.sh - shfile = os.path.join(self.app_home(self.node), "sw_connect.sh") - self.node.upload(switch_connect_command, - shfile, - text = True, - overwrite = False) + if self.check_switch_host_link : + host0, ip0, pname0, virt_ip0, pnumber0 = endpoint1.port_info + return pnumber0 - #invoke connect script - cmd = "bash %s" % shfile - (out, err), proc = self.node.run(cmd, self.run_home(self.node), - sudo = True, - stdout = "sw_stdout", - stderr = "sw_stderr") - - # check if execution errors occured - if proc.poll(): - msg = "Failed to connect endpoints" - self.error(msg, out, err) - raise RuntimeError, msg - - # For debugging - msg = "Connection on port %s configured" % local_port_name - self.info(msg) + host0, ip0, pname0, virt_ip0, pnumber0 = endpoint1.port_info + host1, ip1, pname1, virt_ip1, pnumber1 = endpoint2.port_info - def wait_local_port(self): + return pname0, ip1, pnumber1 + + def wait_local_port(self, node_endpoint): """ Waits until the if_name file for the command is generated, and returns the if_name for the device """ + local_port = None delay = 1.0 + #TODO : Need to change it with reschedule to avoid the problem + # of the order of connection for i in xrange(10): - (out, err), proc = self.node.check_output(self.run_home(self.node), 'local_port') - + (out, err), proc = node_endpoint.check_output(self.run_home(node_endpoint), 'local_port') if out: local_port = int(out) break @@ -332,31 +228,86 @@ class OVSTunnel(LinuxApplication): return local_port - def sw_host_connect(self, endpoint, rem_endpoint): - """Link switch--> host + def connection(self, local_endpoint, rm_endpoint): + """ Create the connect command for each case : + - Host - Switch, + - Switch - Switch, + - Switch - Host """ - # Retrieve remote port number from rem_endpoint - local_port_name = endpoint.get('port_name') - self._nodes = self.get_node(rem_endpoint) - - # time.sleep(4) # Without this, sometimes I get nothing in remote_port_num - out = err= '' - remote_port_num = self.wait_local_port() - remote_ip = socket.gethostbyname(self.node.get("hostname")) - switch_connect_command = endpoint.switch_connect_command( - local_port_name, remote_ip, remote_port_num) - - # Upload command to the file sw_connect.sh - self._nodes = self.get_node(endpoint) - shfile = os.path.join(self.app_home(self.node), "sw_connect.sh") - self.node.upload(switch_connect_command, + local_node = self.get_node(local_endpoint) + local_node.mkdir(self.run_home(local_node)) + + rm_node = self.get_node(rm_endpoint) + rm_node.mkdir(self.run_home(rm_node)) + + # Host to switch + if self.check_switch_host_link and local_endpoint == self.endpoint2 : + # Collect info from rem_endpoint + remote_ip = socket.gethostbyname(rm_node.get("hostname")) + + # Collect info from endpoint + local_port_file = os.path.join(self.run_home(local_node), "local_port") + rem_port_file = os.path.join(self.run_home(local_node), "remote_port") + ret_file = os.path.join(self.run_home(local_node), "ret_file") + cipher = self.get("cipher") + cipher_key = self.get("cipherKey") + bwlimit = self.get("bwLimit") + txqueuelen = self.get("txQueueLen") + + rem_port = str(self.get_port_info(rm_endpoint,local_endpoint)) + + # Upload the remote port in a file + local_node.upload(rem_port, rem_port_file, + text = True, + overwrite = False) + + connect_command = local_endpoint.udp_connect_command( + remote_ip, local_port_file, rem_port_file, + ret_file, cipher, cipher_key, bwlimit, txqueuelen) + + self.connection_command(connect_command, local_node, rm_node) + + # Wait for pid file to be generated + self._pid, self._ppid = local_node.wait_pid(self.run_home(local_node)) + + if not self._pid or not self._ppid: + (out, err), proc = local_node.check_errors(self.run_home(local_node)) + # Out is what was written in the stderr file + if err: + msg = " Failed to start connection of the OVS Tunnel " + self.error(msg, out, err) + raise RuntimeError, msg + return + + # Switch to Host + if self.check_switch_host_link and local_endpoint == self.endpoint1: + local_port_name = local_endpoint.get('port_name') + remote_port_num = self.wait_local_port(rm_node) + remote_ip = socket.gethostbyname(rm_node.get("hostname")) + + # Switch to Switch + if not self.check_switch_host_link : + local_port_name, remote_ip, remote_port_num = self.get_port_info(local_endpoint, rm_endpoint) + + connect_command = local_endpoint.switch_connect_command( + local_port_name, remote_ip, remote_port_num) + + self.connection_command(connect_command, local_node, rm_node) + + def connection_command(self, command, node_endpoint, rm_node_endpoint): + """ Execute the connection command on the node and check if the processus is + correctly running on the node. + """ + shfile = os.path.join(self.app_home(node_endpoint), "sw_connect.sh") + node_endpoint.upload(command, shfile, text = True, overwrite = False) # Invoke connect script + out = err= '' cmd = "bash %s" % shfile - (out, err), proc = self.node.run(cmd, self.run_home(self.node), + (out, err), proc = node_endpoint.run(cmd, self.run_home(node_endpoint), sudo = True, stdout = "sw_stdout", stderr = "sw_stderr") @@ -369,59 +320,37 @@ class OVSTunnel(LinuxApplication): raise RuntimeError, msg # For debugging - msg = "Connection on port %s configured" % local_port_name - self.debug(msg) + msg = "Connection on port configured" + self.debug(msg) def do_provision(self): """ Provision the tunnel """ - # Create folders - self._nodes = self.get_node(self.endpoint1) - self.node.mkdir(self.run_home(self.node)) - self._nodes = self.get_node(self.endpoint2) - self.node.mkdir(self.run_home(self.node)) - - if self.check_endpoints: - #Invoke connect script between switches - self.switch_connect(self.endpoint1, self.endpoint2) - self.switch_connect(self.endpoint2, self.endpoint1) - - else: - # Invoke connect script between switch & host - (self._pid, self._ppid) = self.udp_connect(self.endpoint2, self.endpoint1) - self.sw_host_connect(self.endpoint1, self.endpoint2) - - super(OVSTunnel, self).do_provision() + + #TODO : The order of the connection is important for now ! + # Need to change the code of wait local port + self.connection(self.endpoint2, self.endpoint1) + self.connection(self.endpoint1, self.endpoint2) - @property - def tap(self): - rclass = ResourceFactory.get_resource_type(PlanetlabTap.get_rtype()) - for guid in self.connections: - rm = self.ec.get_resource(guid) - if isinstance(rm, rclass): - return rm + def configure_route(self): + """ Configure the route for the tap device - @property - def ovswitch(self): - for guid in self.connections: - rm_port = self.ec.get_resource(guid) - if hasattr(rm_port, "create_port"): - rm_list = rm_port.get_connected(OVSWitch.get_rtype()) - if rm_list: - return rm_list[0] + .. note : In case of a conection between a switch and a host, a route + was missing on the node with the Tap Device. This method create + the missing route. + """ - def configure(self): - if not self.check_endpoints: + if self.check_switch_host_link: self._vroute = self.ec.register_resource("PlanetlabVroute") self.ec.set(self._vroute, "action", "add") self.ec.set(self._vroute, "network", self.get("network")) self.ec.register_connection(self._vroute, self.tap.guid) - # schedule deploy self.ec.deploy(guids=[self._vroute], group = self.deployment_group) - def do_deploy(self): + """ Deploy the tunnel after the endpoint get ready + """ if (not self.endpoint1 or self.endpoint1.state < ResourceState.READY) or \ (not self.endpoint2 or self.endpoint2.state < ResourceState.READY): self.ec.schedule(reschedule_delay, self.deploy) @@ -429,25 +358,28 @@ class OVSTunnel(LinuxApplication): self.do_discover() self.do_provision() - self.configure() - - super(OVSTunnel, self).do_deploy() + self.configure_route() + + # Cannot call the deploy of the linux application + # because of a log error. + # Need to investigate if it is right that the tunnel + # inherits from the linux application + # super(OVSTunnel, self).do_deploy() + self.set_ready() def do_release(self): - """ Release the udp_tunnel on endpoint2. - On endpoint1 means nothing special. + """ Release the tunnel by releasing the Tap Device if exists """ - if not self.check_endpoints: - # Kill the TAP devices + if self.check_switch_host_link: # TODO: Make more generic Release method of PLTAP + tap_node = self.get_node(self.endpoint2) if self._pid and self._ppid: - self._nodes = self.get_node(self.endpoint2) - (out, err), proc = self.node.kill(self._pid, + (out, err), proc = tap_node.kill(self._pid, self._ppid, sudo = True) + if err or proc.poll(): - # check if execution errors occurred msg = " Failed to delete TAP device" - self.error(msg, err, err) + self.error(msg, out, err) super(OVSTunnel, self).do_release() diff --git a/src/nepi/resources/planetlab/tap.py b/src/nepi/resources/planetlab/tap.py index 5301265d..6d1be501 100644 --- a/src/nepi/resources/planetlab/tap.py +++ b/src/nepi/resources/planetlab/tap.py @@ -230,7 +230,7 @@ class PlanetlabTap(LinuxApplication): if_name = None delay = 1.0 - for i in xrange(10): + for i in xrange(20): (out, err), proc = self.node.check_output(self.run_home, "if_name") if out: diff --git a/test/resources/planetlab/ovs.py b/test/resources/planetlab/ovs.py index d0720740..e76a6e66 100644 --- a/test/resources/planetlab/ovs.py +++ b/test/resources/planetlab/ovs.py @@ -52,7 +52,7 @@ class OvsTestCase(unittest.TestCase): ec.set(node1, "cleanHome", True) ec.set(node1, "cleanProcesses", True) - ovs1 = ec.register_resource("OVSWitch") + ovs1 = ec.register_resource("OVSSwitch") ec.set(ovs1, "bridge_name", "nepi_bridge") ec.set(ovs1, "virtual_ip_pref", "192.168.3.1/24") ec.set(ovs1, "controller_ip", "85.23.168.77") @@ -73,7 +73,7 @@ class OvsTestCase(unittest.TestCase): ec.set(node2, "cleanHome", True) ec.set(node2, "cleanProcesses", True) - ovs2 = ec.register_resource("OVSWitch") + ovs2 = ec.register_resource("OVSSwitch") ec.set(ovs2, "bridge_name", "nepi_bridge") ec.set(ovs2, "virtual_ip_pref", "192.168.3.2/24") ec.set(ovs2, "controller_ip", "85.23.168.77")