backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / ovs / bridge.py
1 # Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2012 Isaku Yamahata <yamahata at private email ne jp>
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 """
18 Wrapper utility library of :py:mod:`ryu.lib.ovs.vsctl`
19 """
20
21 import functools
22 import logging
23
24 from ryu import cfg
25 import ryu.exception as ryu_exc
26 import ryu.lib.dpid as dpid_lib
27 import ryu.lib.ovs.vsctl as ovs_vsctl
28 from ryu.lib.ovs.vsctl import valid_ovsdb_addr
29
30
31 LOG = logging.getLogger(__name__)
32
33 CONF = cfg.CONF
34 CONF.register_opts([
35     cfg.IntOpt('ovsdb-timeout', default=2, help='ovsdb timeout')
36 ])
37
38
39 class OVSBridgeNotFound(ryu_exc.RyuException):
40     message = 'no bridge for datapath_id %(datapath_id)s'
41
42
43 class VifPort(object):
44
45     def __init__(self, port_name, ofport, vif_id, vif_mac, switch):
46         super(VifPort, self).__init__()
47         self.port_name = port_name
48         self.ofport = ofport
49         self.vif_id = vif_id
50         self.vif_mac = vif_mac
51         self.switch = switch
52
53     def __str__(self):
54         return ('iface-id=%s, '
55                 'vif_mac=%s, '
56                 'port_name=%s, '
57                 'ofport=%d, '
58                 'bridge_name=%s' % (self.vif_id,
59                                     self.vif_mac,
60                                     self.port_name,
61                                     self.ofport,
62                                     self.switch.br_name))
63
64
65 class TunnelPort(object):
66
67     def __init__(self, port_name, ofport, tunnel_type, local_ip, remote_ip):
68         super(TunnelPort, self).__init__()
69         self.port_name = port_name
70         self.ofport = ofport
71         self.tunnel_type = tunnel_type
72         self.local_ip = local_ip
73         self.remote_ip = remote_ip
74
75     def __eq__(self, other):
76         return (self.port_name == other.port_name and
77                 self.ofport == other.ofport and
78                 self.tunnel_type == other.tunnel_type and
79                 self.local_ip == other.local_ip and
80                 self.remote_ip == other.remote_ip)
81
82     def __str__(self):
83         return ('port_name=%s, '
84                 'ofport=%s, '
85                 'type=%s, '
86                 'local_ip=%s, '
87                 'remote_ip=%s' % (self.port_name,
88                                   self.ofport,
89                                   self.tunnel_type,
90                                   self.local_ip,
91                                   self.remote_ip))
92
93
94 class OVSBridge(object):
95     """
96     Class to provide wrapper utilities of :py:mod:`ryu.lib.ovs.vsctl.VSCtl`
97
98     ``CONF`` is a instance of ``oslo_config.cfg.ConfigOpts``.
99     Mostly ``self.CONF`` is sufficient to instantiate this class from your Ryu
100     application.
101
102     ``datapath_id`` specifies Datapath ID of the target OVS instance.
103
104     ``ovsdb_addr`` specifies the address of the OVS instance.
105     Automatically validated when you call ``init()`` method.
106     Refer to :py:mod:`ryu.lib.ovs.vsctl.valid_ovsdb_addr` for the format of
107     this address.
108
109     if ``timeout`` is omitted, ``CONF.ovsdb_timeout`` will be used as the
110     default value.
111
112     Usage of ``timeout`` and ``exception`` is the same with ``timeout_sec``
113     and ``exception`` of :py:mod:`ryu.lib.ovs.vsctl.VSCtl.run_command`.
114     """
115
116     def __init__(self, CONF, datapath_id, ovsdb_addr, timeout=None,
117                  exception=None):
118         super(OVSBridge, self).__init__()
119         self.datapath_id = datapath_id
120         self.ovsdb_addr = ovsdb_addr
121         self.vsctl = ovs_vsctl.VSCtl(ovsdb_addr)
122         self.timeout = timeout or CONF.ovsdb_timeout
123         self.exception = exception
124
125         self.br_name = None
126
127     def run_command(self, commands):
128         """
129         Executes the given commands and sends OVSDB messages.
130
131         ``commands`` must be a list of
132         :py:mod:`ryu.lib.ovs.vsctl.VSCtlCommand`.
133
134         The given ``timeout`` and ``exception`` when instantiation will be used
135         to call :py:mod:`ryu.lib.ovs.vsctl.VSCtl.run_command`.
136         """
137         self.vsctl.run_command(commands, self.timeout, self.exception)
138
139     def init(self):
140         """
141         Validates the given ``ovsdb_addr`` and connects to OVS instance.
142
143         If failed to connect to OVS instance or the given ``datapath_id`` does
144         not match with the Datapath ID of the connected OVS instance, raises
145         :py:mod:`ryu.lib.ovs.bridge.OVSBridgeNotFound` exception.
146         """
147         if not valid_ovsdb_addr(self.ovsdb_addr):
148             raise ValueError('Invalid OVSDB address: %s' % self.ovsdb_addr)
149         if self.br_name is None:
150             self.br_name = self._get_bridge_name()
151
152     def _get_bridge_name(self):
153         """ get Bridge name of a given 'datapath_id' """
154         command = ovs_vsctl.VSCtlCommand(
155             'find',
156             ('Bridge',
157              'datapath_id=%s' % dpid_lib.dpid_to_str(self.datapath_id)))
158         self.run_command([command])
159         if not isinstance(command.result, list) or len(command.result) != 1:
160             raise OVSBridgeNotFound(
161                 datapath_id=dpid_lib.dpid_to_str(self.datapath_id))
162         return command.result[0].name
163
164     def get_controller(self):
165         """
166         Gets the configured OpenFlow controller address.
167
168         This method is corresponding to the following ovs-vsctl command::
169
170             $ ovs-vsctl get-controller <bridge>
171         """
172         command = ovs_vsctl.VSCtlCommand('get-controller', [self.br_name])
173         self.run_command([command])
174         result = command.result
175         return result[0] if len(result) == 1 else result
176
177     def set_controller(self, controllers):
178         """
179         Sets the OpenFlow controller address.
180
181         This method is corresponding to the following ovs-vsctl command::
182
183             $ ovs-vsctl set-controller <bridge> <target>...
184         """
185         command = ovs_vsctl.VSCtlCommand('set-controller', [self.br_name])
186         command.args.extend(controllers)
187         self.run_command([command])
188
189     def del_controller(self):
190         """
191         Deletes the configured OpenFlow controller address.
192
193         This method is corresponding to the following ovs-vsctl command::
194
195             $ ovs-vsctl del-controller <bridge>
196         """
197         command = ovs_vsctl.VSCtlCommand('del-controller', [self.br_name])
198         self.run_command([command])
199
200     def list_db_attributes(self, table, record=None):
201         """
202         Lists 'record' (or all records) in 'table'.
203
204         This method is corresponding to the following ovs-vsctl command::
205
206             $ ovs-vsctl list TBL [REC]
207         """
208         command = ovs_vsctl.VSCtlCommand('list', (table, record))
209         self.run_command([command])
210         if command.result:
211             return command.result
212         return []
213
214     def find_db_attributes(self, table, *conditions):
215         """
216         Lists records satisfying 'conditions' in 'table'.
217
218         This method is corresponding to the following ovs-vsctl command::
219
220             $ ovs-vsctl find TBL CONDITION...
221
222         .. Note::
223
224             Currently, only '=' condition is supported.
225             To support other condition is TODO.
226         """
227         args = [table]
228         args.extend(conditions)
229         command = ovs_vsctl.VSCtlCommand('find', args)
230         self.run_command([command])
231         if command.result:
232             return command.result
233         return []
234
235     def get_db_attribute(self, table, record, column, key=None):
236         """
237         Gets values of 'column' in 'record' in 'table'.
238
239         This method is corresponding to the following ovs-vsctl command::
240
241             $ ovs-vsctl get TBL REC COL[:KEY]
242         """
243         if key is not None:
244             column = '%s:%s' % (column, key)
245         command = ovs_vsctl.VSCtlCommand(
246             'get', (table, record, column))
247         self.run_command([command])
248         if command.result:
249             return command.result[0]
250         return None
251
252     def set_db_attribute(self, table, record, column, value, key=None):
253         """
254         Sets 'value' into 'column' in 'record' in 'table'.
255
256         This method is corresponding to the following ovs-vsctl command::
257
258             $ ovs-vsctl set TBL REC COL[:KEY]=VALUE
259         """
260         if key is not None:
261             column = '%s:%s' % (column, key)
262         command = ovs_vsctl.VSCtlCommand(
263             'set', (table, record, '%s=%s' % (column, value)))
264         self.run_command([command])
265
266     def add_db_attribute(self, table, record, column, value, key=None):
267         """
268         Adds ('key'=)'value' into 'column' in 'record' in 'table'.
269
270         This method is corresponding to the following ovs-vsctl command::
271
272             $ ovs-vsctl add TBL REC COL [KEY=]VALUE
273         """
274         if key is not None:
275             value = '%s=%s' % (key, value)
276         command = ovs_vsctl.VSCtlCommand(
277             'add', (table, record, column, value))
278         self.run_command([command])
279
280     def remove_db_attribute(self, table, record, column, value, key=None):
281         """
282         Removes ('key'=)'value' into 'column' in 'record' in 'table'.
283
284         This method is corresponding to the following ovs-vsctl command::
285
286             $ ovs-vsctl remove TBL REC COL [KEY=]VALUE
287         """
288         if key is not None:
289             value = '%s=%s' % (key, value)
290         command = ovs_vsctl.VSCtlCommand(
291             'remove', (table, record, column, value))
292         self.run_command([command])
293
294     def clear_db_attribute(self, table, record, column):
295         """
296         Clears values from 'column' in 'record' in 'table'.
297
298         This method is corresponding to the following ovs-vsctl command::
299
300             $ ovs-vsctl clear TBL REC COL
301         """
302         command = ovs_vsctl.VSCtlCommand('clear', (table, record, column))
303         self.run_command([command])
304
305     def db_get_val(self, table, record, column):
306         """
307         Gets values of 'column' in 'record' in 'table'.
308
309         This method is corresponding to the following ovs-vsctl command::
310
311             $ ovs-vsctl get TBL REC COL
312         """
313         command = ovs_vsctl.VSCtlCommand('get', (table, record, column))
314         self.run_command([command])
315         assert len(command.result) == 1
316         return command.result[0]
317
318     def db_get_map(self, table, record, column):
319         """
320         Gets dict type value of 'column' in 'record' in 'table'.
321
322         This method is corresponding to the following ovs-vsctl command::
323
324             $ ovs-vsctl get TBL REC COL
325         """
326         val = self.db_get_val(table, record, column)
327         assert isinstance(val, dict)
328         return val
329
330     def get_datapath_id(self):
331         """
332         Gets Datapath ID of OVS instance.
333
334         This method is corresponding to the following ovs-vsctl command::
335
336             $ ovs-vsctl get Bridge <bridge> datapath_id
337         """
338         return self.db_get_val('Bridge', self.br_name, 'datapath_id')
339
340     def delete_port(self, port_name):
341         """
342         Deletes a port on the OVS instance.
343
344         This method is corresponding to the following ovs-vsctl command::
345
346             $ ovs-vsctl --if-exists del-port <bridge> <port>
347         """
348         command = ovs_vsctl.VSCtlCommand(
349             'del-port', (self.br_name, port_name), '--if-exists')
350         self.run_command([command])
351
352     def get_ofport(self, port_name):
353         """
354         Gets the OpenFlow port number.
355
356         This method is corresponding to the following ovs-vsctl command::
357
358             $ ovs-vsctl get Interface <port> ofport
359         """
360         ofport_list = self.db_get_val('Interface', port_name, 'ofport')
361         assert len(ofport_list) == 1
362         return int(ofport_list[0])
363
364     def get_port_name_list(self):
365         """
366         Gets a list of all ports on OVS instance.
367
368         This method is corresponding to the following ovs-vsctl command::
369
370             $ ovs-vsctl list-ports <bridge>
371         """
372         command = ovs_vsctl.VSCtlCommand('list-ports', (self.br_name, ))
373         self.run_command([command])
374         return command.result
375
376     def add_bond(self, name, ifaces, bond_mode=None, lacp=None):
377         """
378         Creates a bonded port.
379
380         :param name: Port name to be created
381         :param ifaces: List of interfaces containing at least 2 interfaces
382         :param bond_mode: Bonding mode (active-backup, balance-tcp
383                           or balance-slb)
384         :param lacp: LACP mode (active, passive or off)
385         """
386         assert len(ifaces) >= 2
387
388         options = ''
389         if bond_mode:
390             options += 'bond_mode=%(bond_mode)s' % locals()
391         if lacp:
392             options += 'lacp=%(lacp)s' % locals()
393
394         command_add = ovs_vsctl.VSCtlCommand(
395             'add-bond', (self.br_name, name, ifaces), options)
396         self.run_command([command_add])
397
398     def add_tunnel_port(self, name, tunnel_type, remote_ip,
399                         local_ip=None, key=None, ofport=None):
400         """
401         Creates a tunnel port.
402
403         :param name: Port name to be created
404         :param tunnel_type: Type of tunnel (gre or vxlan)
405         :param remote_ip: Remote IP address of tunnel
406         :param local_ip: Local IP address of tunnel
407         :param key: Key of GRE or VNI of VxLAN
408         :param ofport: Requested OpenFlow port number
409         """
410         options = 'remote_ip=%(remote_ip)s' % locals()
411         if key:
412             options += ',key=%(key)s' % locals()
413         if local_ip:
414             options += ',local_ip=%(local_ip)s' % locals()
415
416         args = ['Interface', name, 'type=%s' % tunnel_type,
417                 'options:%s' % options]
418         if ofport:
419             args.append('ofport_request=%(ofport)s' % locals())
420
421         command_add = ovs_vsctl.VSCtlCommand('add-port', (self.br_name, name))
422         command_set = ovs_vsctl.VSCtlCommand('set', args)
423         self.run_command([command_add, command_set])
424
425     def add_gre_port(self, name, remote_ip,
426                      local_ip=None, key=None, ofport=None):
427         """
428         Creates a GRE tunnel port.
429
430         See the description of ``add_tunnel_port()``.
431         """
432         self.add_tunnel_port(name, 'gre', remote_ip,
433                              local_ip=local_ip, key=key, ofport=ofport)
434
435     def add_vxlan_port(self, name, remote_ip,
436                        local_ip=None, key=None, ofport=None):
437         """
438         Creates a VxLAN tunnel port.
439
440         See the description of ``add_tunnel_port()``.
441         """
442         self.add_tunnel_port(name, 'vxlan', remote_ip,
443                              local_ip=local_ip, key=key, ofport=ofport)
444
445     def del_port(self, port_name):
446         """
447         Deletes a port on OVS instance.
448
449         This method is corresponding to the following ovs-vsctl command::
450
451             $ ovs-vsctl del-port <bridge> <port>
452         """
453         command = ovs_vsctl.VSCtlCommand('del-port', (self.br_name, port_name))
454         self.run_command([command])
455
456     def _get_ports(self, get_port):
457         ports = []
458         port_names = self.get_port_name_list()
459         for name in port_names:
460             if self.get_ofport(name) < 0:
461                 continue
462             port = get_port(name)
463             if port:
464                 ports.append(port)
465
466         return ports
467
468     def _vifport(self, name, external_ids):
469         ofport = self.get_ofport(name)
470         return VifPort(name, ofport, external_ids['iface-id'],
471                        external_ids['attached-mac'], self)
472
473     def _get_vif_port(self, name):
474         external_ids = self.db_get_map('Interface', name, 'external_ids')
475         if 'iface-id' in external_ids and 'attached-mac' in external_ids:
476             return self._vifport(name, external_ids)
477
478     def get_vif_ports(self):
479         """ Returns a VIF object for each VIF port """
480         return self._get_ports(self._get_vif_port)
481
482     def _get_external_port(self, name):
483         # exclude vif ports
484         external_ids = self.db_get_map('Interface', name, 'external_ids')
485         if external_ids:
486             return
487
488         # exclude tunnel ports
489         options = self.db_get_map('Interface', name, 'options')
490         if 'remote_ip' in options:
491             return
492
493         ofport = self.get_ofport(name)
494         return VifPort(name, ofport, None, None, self)
495
496     def get_external_ports(self):
497         return self._get_ports(self._get_external_port)
498
499     def get_tunnel_port(self, name, tunnel_type='gre'):
500         type_ = self.db_get_val('Interface', name, 'type')
501         if type_ != tunnel_type:
502             return
503
504         options = self.db_get_map('Interface', name, 'options')
505         if 'local_ip' in options and 'remote_ip' in options:
506             ofport = self.get_ofport(name)
507             return TunnelPort(name, ofport, tunnel_type,
508                               options['local_ip'], options['remote_ip'])
509
510     def get_tunnel_ports(self, tunnel_type='gre'):
511         get_tunnel_port = functools.partial(self.get_tunnel_port,
512                                             tunnel_type=tunnel_type)
513         return self._get_ports(get_tunnel_port)
514
515     def get_quantum_ports(self, port_name):
516         LOG.debug('port_name %s', port_name)
517         command = ovs_vsctl.VSCtlCommand(
518             'list-ifaces-verbose',
519             [dpid_lib.dpid_to_str(self.datapath_id), port_name])
520         self.run_command([command])
521         if command.result:
522             return command.result[0]
523         return None
524
525     def set_qos(self, port_name, type='linux-htb', max_rate=None, queues=None):
526         """
527         Sets a Qos rule and creates Queues on the given port.
528         """
529         queues = queues if queues else []
530         command_qos = ovs_vsctl.VSCtlCommand(
531             'set-qos',
532             [port_name, type, max_rate])
533         command_queue = ovs_vsctl.VSCtlCommand(
534             'set-queue',
535             [port_name, queues])
536         self.run_command([command_qos, command_queue])
537         if command_qos.result and command_queue.result:
538             return command_qos.result + command_queue.result
539         return None
540
541     def del_qos(self, port_name):
542         """
543         Deletes the Qos rule on the given port.
544         """
545         command = ovs_vsctl.VSCtlCommand(
546             'del-qos',
547             [port_name])
548         self.run_command([command])