2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2013 INRIA
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License version 2 as
7 # published by the Free Software Foundation;
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 # Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
18 # Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
19 # Julien Tribino <julien.tribino@inria.fr>
21 from nepi.execution.attribute import Attribute, Flags, Types
22 from nepi.execution.resource import ResourceManager, clsinit_copy, \
24 from nepi.resources.planetlab.openvswitch.ovs import PlanetlabOVSSwitch
25 from nepi.resources.planetlab.node import PlanetlabNode
26 from nepi.resources.linux.application import LinuxApplication
31 class PlanetlabOVSPort(LinuxApplication):
33 .. class:: Class Args :
35 :param ec: The Experiment controller
36 :type ec: ExperimentController
37 :param guid: guid of the RM
42 _rtype = "planetlab::OVSPort"
43 _help = "Runs an OpenVSwitch on a PlanetLab host"
44 _platform = "planetlab"
46 _authorized_connections = ["planetlab::OVSSwitch", "linux::UdpTunnel", "linux::Tunnel"]
49 def _register_attributes(cls):
50 """ Register the attributes of OVSPort RM
53 port_name = Attribute("port_name", "Name of the port",
55 ip = Attribute("ip", "IP of the endpoint. This is the attribute "
56 "you should use to establish a tunnel or a remote "
57 "connection between endpoint",
59 network = Attribute("network", "Network used by the port",
62 cls._register_attribute(port_name)
63 cls._register_attribute(ip)
64 cls._register_attribute(network)
66 def __init__(self, ec, guid):
68 :param ec: The Experiment controller
69 :type ec: ExperimentController
70 :param guid: guid of the RM
74 super(PlanetlabOVSPort, self).__init__(ec, guid)
75 self._home = "ovsport-%s" % self.guid
76 self._port_number = None
80 """ Node that run the switch and the ports
82 return self.ovsswitch.node
86 """ Switch where the port is created
88 ovsswitch = self.get_connected(PlanetlabOVSSwitch.get_rtype())
89 if ovsswitch: return ovsswitch[0]
93 def port_number(self):
94 return self._port_number
96 def valid_connection(self, guid):
97 """ Check if the connection is available.
99 :param guid: Guid of the current RM
104 rm = self.ec.get_resource(guid)
105 if rm.get_rtype() not in self._authorized_connections:
110 def create_port(self):
111 """ Create the desired port
113 msg = "Creating the port %s" % self.get('port_name')
116 if not self.get('port_name'):
117 msg = "The port name is not assigned"
119 raise AttributeError, msg
121 if not self.ovsswitch:
122 msg = "The OVSwitch RM is not running"
124 raise AttributeError, msg
126 command = "sliver-ovs create-port %s %s" % (
127 self.ovsswitch.get('bridge_name'),
128 self.get('port_name'))
130 shfile = os.path.join(self.app_home, "create_port.sh")
132 self.node.run_and_wait(command, self.run_home,
135 stderr="port_stdout",
136 stdout="port_stderr",
137 pidfile="port_pidfile",
138 ecodefile="port_exitcode")
140 msg = "Could not create ovs-port"
142 raise RuntimeError, msg
144 self.info("Created port %s on switch %s" % (
145 self.get('port_name'),
146 self.ovsswitch.get('bridge_name')))
148 def initiate_udp_connection(self, remote_endpoint, connection_app_home,
149 connection_run_home, cipher, cipher_key, bwlimit, txqueuelen):
150 """ Get the local_endpoint of the port
152 msg = "Discovering the port number for %s" % self.get('port_name')
155 command = "sliver-ovs get-local-endpoint %s" % self.get('port_name')
157 shfile = os.path.join(connection_app_home, "get_port.sh")
158 (out, err), proc = self.node.run_and_wait(command, connection_run_home,
162 pidfile="get_port_pidfile",
163 ecodefile="get_port_exitcode",
164 stdout="get_port_stdout",
165 stderr="get_port_stderr")
168 msg = "Error retrieving the local endpoint of the port"
170 raise RuntimeError, msg
173 self._port_number = out.strip()
175 self.info("The number of the %s is %s" % (self.get('port_name'),
178 # Must set a routing rule in the ovs client nodes so they know
179 # that the LAN can be found through the switch
180 if remote_endpoint.is_rm_instance("planetlab::Tap"):
181 self._vroute = self.ec.register_resource("planetlab::Vroute")
182 self.ec.set(self._vroute, "action", "add")
183 self.ec.set(self._vroute, "prefix", remote_endpoint.get("prefix"))
184 self.ec.set(self._vroute, "nexthop", remote_endpoint.get("pointopoint"))
185 self.ec.set(self._vroute, "network", self.get("network"))
187 self.ec.register_connection(self._vroute, remote_endpoint.guid)
188 self.ec.deploy(guids=[self._vroute], group = self.deployment_group)
191 msg = "Route for the tap configured"
194 return self.port_number
196 def establish_udp_connection(self, remote_endpoint,
200 remote_ip = remote_endpoint.node.get("ip")
201 command = self._establish_connection_command(port, remote_ip)
203 shfile = os.path.join(connection_app_home, "connect_port.sh")
204 (out, err), proc = self.node.run_and_wait(command, connection_run_home,
208 pidfile="connect_port_pidfile",
209 ecodefile="connect_port_exitcode",
210 stdout="connect_port_stdout",
211 stderr="connect_port_stderr")
214 msg = "Connection on port configured"
217 def _establish_connection_command(self, port, remote_ip):
218 """ Script to create the connection from a switch to a
221 local_port_name = self.get('port_name')
223 command = ["sliver-ovs"]
224 command.append("set-remote-endpoint")
225 command.append(local_port_name)
226 command.append(remote_ip)
228 command = " ".join(command)
229 command = self.replace_paths(command)
232 def verify_connection(self, remote_endpoint, connection_app_home,
233 connection_run_home):
234 self.ovsswitch.ovs_status()
236 def terminate_connection(self, endpoint, connection_app_home,
237 connection_run_home):
240 def check_status(self):
241 return self.node.status(self._pid, self._ppid)
243 def do_provision(self):
244 self.node.mkdir(self.run_home)
247 end_ip = self.ovsswitch.get('virtual_ip_pref').split('/')
248 self.set("ip", end_ip[0])
250 #Check the status of the OVS Switch
251 self.ovsswitch.ovs_status()
253 self.set_provisioned()
256 """ Deploy the OVS port after the OVS Switch
258 if not self.ovsswitch or self.ovsswitch.state < ResourceState.READY:
259 self.debug("---- RESCHEDULING DEPLOY ---- OVSwitch state %s " % self.ovsswitch.state )
260 self.ec.schedule(self.reschedule_delay, self.deploy)
267 def do_release(self):
268 """ Delete the port on the OVSwitch. It needs to wait for the tunnel
271 from nepi.resources.linux.udptunnel import LinuxUdpTunnel
272 rm = self.get_connected(LinuxUdpTunnel.get_rtype())
274 if rm and rm[0].state < ResourceState.STOPPED:
275 self.ec.schedule(self.reschedule_delay, self.release)
278 msg = "Deleting the port %s" % self.get('port_name')
281 command = "sliver-ovs del_port %s" % self.get('port_name')
283 shfile = os.path.join(self.app_home, "stop.sh")
284 self.node.run_and_wait(command, self.run_home,
287 pidfile="stop_pidfile",
288 ecodefile="stop_exitcode",
289 stdout="stop_stdout",
290 stderr="stop_stderr")
292 super(PlanetlabOVSPort, self).do_release()