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 as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
19 # Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
20 # Julien Tribino <julien.tribino@inria.fr>
22 from nepi.execution.attribute import Attribute, Flags, Types
23 from nepi.execution.resource import ResourceManager, clsinit_copy, \
25 from nepi.resources.planetlab.openvswitch.ovs import PlanetlabOVSSwitch
26 from nepi.resources.planetlab.node import PlanetlabNode
27 from nepi.resources.linux.application import LinuxApplication
32 class PlanetlabOVSPort(LinuxApplication):
34 .. class:: Class Args :
36 :param ec: The Experiment controller
37 :type ec: ExperimentController
38 :param guid: guid of the RM
43 _rtype = "planetlab::OVSPort"
44 _help = "Runs an OpenVSwitch on a PlanetLab host"
45 _platform = "planetlab"
47 _authorized_connections = ["planetlab::OVSSwitch", "linux::UdpTunnel", "linux::Tunnel"]
50 def _register_attributes(cls):
51 """ Register the attributes of OVSPort RM
54 port_name = Attribute("port_name", "Name of the port",
56 ip = Attribute("ip", "IP of the endpoint. This is the attribute "
57 "you should use to establish a tunnel or a remote "
58 "connection between endpoint",
60 network = Attribute("network", "Network used by the port",
63 cls._register_attribute(port_name)
64 cls._register_attribute(ip)
65 cls._register_attribute(network)
67 def __init__(self, ec, guid):
69 :param ec: The Experiment controller
70 :type ec: ExperimentController
71 :param guid: guid of the RM
75 super(PlanetlabOVSPort, self).__init__(ec, guid)
76 self._home = "ovsport-%s" % self.guid
77 self._port_number = None
81 """ Node that run the switch and the ports
83 return self.ovsswitch.node
87 """ Switch where the port is created
89 ovsswitch = self.get_connected(PlanetlabOVSSwitch.get_rtype())
90 if ovsswitch: return ovsswitch[0]
94 def port_number(self):
95 return self._port_number
97 def valid_connection(self, guid):
98 """ Check if the connection is available.
100 :param guid: Guid of the current RM
105 rm = self.ec.get_resource(guid)
106 if rm.get_rtype() not in self._authorized_connections:
111 def create_port(self):
112 """ Create the desired port
114 msg = "Creating the port %s" % self.get('port_name')
117 if not self.get('port_name'):
118 msg = "The port name is not assigned"
120 raise AttributeError, msg
122 if not self.ovsswitch:
123 msg = "The OVSwitch RM is not running"
125 raise AttributeError, msg
127 command = "sliver-ovs create-port %s %s" % (
128 self.ovsswitch.get('bridge_name'),
129 self.get('port_name'))
131 shfile = os.path.join(self.app_home, "create_port.sh")
133 self.node.run_and_wait(command, self.run_home,
136 stderr="port_stdout",
137 stdout="port_stderr",
138 pidfile="port_pidfile",
139 ecodefile="port_exitcode")
141 msg = "Could not create ovs-port"
143 raise RuntimeError, msg
145 self.info("Created port %s on switch %s" % (
146 self.get('port_name'),
147 self.ovsswitch.get('bridge_name')))
149 def initiate_udp_connection(self, remote_endpoint, connection_app_home,
150 connection_run_home, cipher, cipher_key, bwlimit, txqueuelen):
151 """ Get the local_endpoint of the port
153 msg = "Discovering the port number for %s" % self.get('port_name')
156 command = "sliver-ovs get-local-endpoint %s" % self.get('port_name')
158 shfile = os.path.join(connection_app_home, "get_port.sh")
159 (out, err), proc = self.node.run_and_wait(command, connection_run_home,
163 pidfile="get_port_pidfile",
164 ecodefile="get_port_exitcode",
165 stdout="get_port_stdout",
166 stderr="get_port_stderr")
169 msg = "Error retrieving the local endpoint of the port"
171 raise RuntimeError, msg
174 self._port_number = out.strip()
176 self.info("The number of the %s is %s" % (self.get('port_name'),
179 # Must set a routing rule in the ovs client nodes so they know
180 # that the LAN can be found through the switch
181 if remote_endpoint.is_rm_instance("planetlab::Tap"):
182 self._vroute = self.ec.register_resource("planetlab::Vroute")
183 self.ec.set(self._vroute, "action", "add")
184 self.ec.set(self._vroute, "prefix", remote_endpoint.get("prefix"))
185 self.ec.set(self._vroute, "nexthop", remote_endpoint.get("pointopoint"))
186 self.ec.set(self._vroute, "network", self.get("network"))
188 self.ec.register_connection(self._vroute, remote_endpoint.guid)
189 self.ec.deploy(guids=[self._vroute], group = self.deployment_group)
192 msg = "Route for the tap configured"
195 return self.port_number
197 def establish_udp_connection(self, remote_endpoint,
201 remote_ip = remote_endpoint.node.get("ip")
202 command = self._establish_connection_command(port, remote_ip)
204 shfile = os.path.join(connection_app_home, "connect_port.sh")
205 (out, err), proc = self.node.run_and_wait(command, connection_run_home,
209 pidfile="connect_port_pidfile",
210 ecodefile="connect_port_exitcode",
211 stdout="connect_port_stdout",
212 stderr="connect_port_stderr")
215 msg = "Connection on port configured"
218 def _establish_connection_command(self, port, remote_ip):
219 """ Script to create the connection from a switch to a
222 local_port_name = self.get('port_name')
224 command = ["sliver-ovs"]
225 command.append("set-remote-endpoint")
226 command.append(local_port_name)
227 command.append(remote_ip)
229 command = " ".join(command)
230 command = self.replace_paths(command)
233 def verify_connection(self, remote_endpoint, connection_app_home,
234 connection_run_home):
235 self.ovsswitch.ovs_status()
237 def terminate_connection(self, endpoint, connection_app_home,
238 connection_run_home):
241 def check_status(self):
242 return self.node.status(self._pid, self._ppid)
244 def do_provision(self):
245 self.node.mkdir(self.run_home)
248 end_ip = self.ovsswitch.get('virtual_ip_pref').split('/')
249 self.set("ip", end_ip[0])
251 #Check the status of the OVS Switch
252 self.ovsswitch.ovs_status()
254 self.set_provisioned()
257 """ Deploy the OVS port after the OVS Switch
259 if not self.ovsswitch or self.ovsswitch.state < ResourceState.READY:
260 self.debug("---- RESCHEDULING DEPLOY ---- OVSwitch state %s " % self.ovsswitch.state )
261 self.ec.schedule(self.reschedule_delay, self.deploy)
268 def do_release(self):
269 """ Delete the port on the OVSwitch. It needs to wait for the tunnel
272 from nepi.resources.linux.udptunnel import LinuxUdpTunnel
273 rm = self.get_connected(LinuxUdpTunnel.get_rtype())
275 if rm and rm[0].state < ResourceState.STOPPED:
276 self.ec.schedule(self.reschedule_delay, self.release)
279 msg = "Deleting the port %s" % self.get('port_name')
282 command = "sliver-ovs del_port %s" % self.get('port_name')
284 shfile = os.path.join(self.app_home, "stop.sh")
285 self.node.run_and_wait(command, self.run_home,
288 pidfile="stop_pidfile",
289 ecodefile="stop_exitcode",
290 stdout="stop_stdout",
291 stderr="stop_stderr")
293 super(PlanetlabOVSPort, self).do_release()