summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/source/library.rst1
-rw-r--r--doc/source/library_ovsdb.rst76
-rw-r--r--ryu/lib/ovs/bridge.py134
-rw-r--r--ryu/lib/ovs/vsctl.py57
4 files changed, 264 insertions, 4 deletions
diff --git a/doc/source/library.rst b/doc/source/library.rst
index ff280415..cdaed768 100644
--- a/doc/source/library.rst
+++ b/doc/source/library.rst
@@ -15,3 +15,4 @@ Ryu provides some useful library for your network applications.
library_bgp_speaker_ref.rst
library_mrt.rst
library_ovsdb_manager.rst
+ library_ovsdb.rst
diff --git a/doc/source/library_ovsdb.rst b/doc/source/library_ovsdb.rst
new file mode 100644
index 00000000..df7d1708
--- /dev/null
+++ b/doc/source/library_ovsdb.rst
@@ -0,0 +1,76 @@
+*************
+OVSDB library
+*************
+
+Path: ``ryu.lib.ovs``
+
+Similar to the :doc:`library_ovsdb_manager`, this library enables your
+application to speak the OVSDB protocol (RFC7047_), but differ from the
+:doc:`library_ovsdb_manager`, this library will initiate connections from
+controller side as ovs-vsctl_ command does.
+Please make sure that your devices are listening on either the Unix domain
+socket or TCP/SSL port before calling the APIs of this library.
+
+.. code-block:: bash
+
+ # Show current configuration
+ $ ovs-vsctl get-manager
+
+ # Set TCP listen address
+ $ ovs-vsctl set-manager "ptcp:6640"
+
+See manpage of ovs-vsctl_ command for more details.
+
+.. _RFC7047: https://tools.ietf.org/html/rfc7047
+.. _ovs-vsctl: http://openvswitch.org/support/dist-docs/ovs-vsctl.8.txt
+
+Basic Usage
+===========
+
+1. Instantiate :py:mod:`ryu.lib.ovs.vsctl.VSCtl`.
+
+2. Construct commands with :py:mod:`ryu.lib.ovs.vsctl.VSCtlCommand`.
+ The syntax is almost the same as ovs-vsctl_ command.
+
+3. Execute commands via :py:mod:`ryu.lib.ovs.vsctl.VSCtl.run_command`.
+
+Example
+-------
+
+.. code-block:: python
+
+ from ryu.lib.ovs import vsctl
+
+ OVSDB_ADDR = 'tcp:127.0.0.1:6640'
+ ovs_vsctl = vsctl.VSCtl(OVSDB_ADDR)
+
+ # Equivalent to
+ # $ ovs-vsctl show
+ command = vsctl.VSCtlCommand('show')
+ ovs_vsctl.run_command([command])
+ print(command)
+ # >>> VSCtlCommand(args=[],command='show',options=[],result='830d781f-c3c8-4b4f-837e-106e1b33d058\n ovs_version: "2.8.90"\n')
+
+ # Equivalent to
+ # $ ovs-vsctl list Port s1-eth1
+ command = vsctl.VSCtlCommand('list', ('Port', 's1-eth1'))
+ ovs_vsctl.run_command([command])
+ print(command)
+ # >>> VSCtlCommand(args=('Port', 's1-eth1'),command='list',options=[],result=[<ovs.db.idl.Row object at 0x7f525fb682e8>])
+ print(command.result[0].name)
+ # >>> s1-eth1
+
+API Reference
+=============
+
+ryu.lib.ovs.vsctl
+-----------------
+
+.. automodule:: ryu.lib.ovs.vsctl
+ :members:
+
+ryu.lib.ovs.bridge
+------------------
+
+.. automodule:: ryu.lib.ovs.bridge
+ :members:
diff --git a/ryu/lib/ovs/bridge.py b/ryu/lib/ovs/bridge.py
index e48052fb..9753fa29 100644
--- a/ryu/lib/ovs/bridge.py
+++ b/ryu/lib/ovs/bridge.py
@@ -15,7 +15,7 @@
# limitations under the License.
"""
-slimmed down version of OVSBridge in quantum agent
+Wrapper utility library of :py:mod:`ryu.lib.ovs.vsctl`
"""
import functools
@@ -92,6 +92,26 @@ class TunnelPort(object):
class OVSBridge(object):
+ """
+ Class to provide wrapper utilities of :py:mod:`ryu.lib.ovs.vsctl.VSCtl`
+
+ ``CONF`` is a instance of ``oslo_config.cfg.ConfigOpts``.
+ Mostly ``self.CONF`` is sufficient to instantiate this class from your Ryu
+ application.
+
+ ``datapath_id`` specifies Datapath ID of the target OVS instance.
+
+ ``ovsdb_addr`` specifies the address of the OVS instance.
+ Automatically validated when you call ``init()`` method.
+ Refer to :py:mod:`ryu.lib.ovs.vsctl.valid_ovsdb_addr` for the format of
+ this address.
+
+ if ``timeout`` is omitted, ``CONF.ovsdb_timeout`` will be used as the
+ default value.
+
+ Usage of ``timeout`` and ``exception`` is the same with ``timeout_sec``
+ and ``exception`` of :py:mod:`ryu.lib.ovs.vsctl.VSCtl.run_command`.
+ """
def __init__(self, CONF, datapath_id, ovsdb_addr, timeout=None,
exception=None):
@@ -105,9 +125,25 @@ class OVSBridge(object):
self.br_name = None
def run_command(self, commands):
+ """
+ Executes the given commands and sends OVSDB messages.
+
+ ``commands`` must be a list of
+ :py:mod:`ryu.lib.ovs.vsctl.VSCtlCommand`.
+
+ The given ``timeout`` and ``exception`` when instantiation will be used
+ to call :py:mod:`ryu.lib.ovs.vsctl.VSCtl.run_command`.
+ """
self.vsctl.run_command(commands, self.timeout, self.exception)
def init(self):
+ """
+ Validates the given ``ovsdb_addr`` and connects to OVS instance.
+
+ If failed to connect to OVS instance or the given ``datapath_id`` does
+ not match with the Datapath ID of the connected OVS instance, raises
+ :py:mod:`ryu.lib.ovs.bridge.OVSBridgeNotFound` exception.
+ """
if not valid_ovsdb_addr(self.ovsdb_addr):
raise ValueError('Invalid OVSDB address: %s' % self.ovsdb_addr)
if self.br_name is None:
@@ -126,16 +162,37 @@ class OVSBridge(object):
return command.result[0].name
def get_controller(self):
+ """
+ Gets the configured OpenFlow controller address.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl get-controller <bridge>
+ """
command = ovs_vsctl.VSCtlCommand('get-controller', [self.br_name])
self.run_command([command])
return command.result[0]
def set_controller(self, controllers):
+ """
+ Sets the OpenFlow controller address.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl set-controller <bridge> <target>...
+ """
command = ovs_vsctl.VSCtlCommand('set-controller', [self.br_name])
command.args.extend(controllers)
self.run_command([command])
def del_controller(self):
+ """
+ Deletes the configured OpenFlow controller address.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl del-controller <bridge>
+ """
command = ovs_vsctl.VSCtlCommand('del-controller', [self.br_name])
self.run_command([command])
@@ -245,30 +302,72 @@ class OVSBridge(object):
self.run_command([command])
def db_get_val(self, table, record, column):
+ """
+ Gets values of 'column' in 'record' in 'table'.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl get TBL REC COL
+ """
command = ovs_vsctl.VSCtlCommand('get', (table, record, column))
self.run_command([command])
assert len(command.result) == 1
return command.result[0]
def db_get_map(self, table, record, column):
+ """
+ Gets dict type value of 'column' in 'record' in 'table'.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl get TBL REC COL
+ """
val = self.db_get_val(table, record, column)
assert isinstance(val, dict)
return val
def get_datapath_id(self):
+ """
+ Gets Datapath ID of OVS instance.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl get Bridge <bridge> datapath_id
+ """
return self.db_get_val('Bridge', self.br_name, 'datapath_id')
def delete_port(self, port_name):
+ """
+ Deletes a port on the OVS instance.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl --if-exists del-port <bridge> <port>
+ """
command = ovs_vsctl.VSCtlCommand(
'del-port', (self.br_name, port_name), '--if-exists')
self.run_command([command])
def get_ofport(self, port_name):
+ """
+ Gets the OpenFlow port number.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl get Interface <port> ofport
+ """
ofport_list = self.db_get_val('Interface', port_name, 'ofport')
assert len(ofport_list) == 1
return int(ofport_list[0])
def get_port_name_list(self):
+ """
+ Gets a list of all ports on OVS instance.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl list-ports <bridge>
+ """
command = ovs_vsctl.VSCtlCommand('list-ports', (self.br_name, ))
self.run_command([command])
return command.result
@@ -297,6 +396,16 @@ class OVSBridge(object):
def add_tunnel_port(self, name, tunnel_type, remote_ip,
local_ip=None, key=None, ofport=None):
+ """
+ Creates a tunnel port.
+
+ :param name: Port name to be created
+ :param tunnel_type: Type of tunnel (gre or vxlan)
+ :param remote_ip: Remote IP address of tunnel
+ :param local_ip: Local IP address of tunnel
+ :param key: Key of GRE or VNI of VxLAN
+ :param ofport: Requested OpenFlow port number
+ """
options = 'remote_ip=%(remote_ip)s' % locals()
if key:
options += ',key=%(key)s' % locals()
@@ -314,15 +423,32 @@ class OVSBridge(object):
def add_gre_port(self, name, remote_ip,
local_ip=None, key=None, ofport=None):
+ """
+ Creates a GRE tunnel port.
+
+ See the description of ``add_tunnel_port()``.
+ """
self.add_tunnel_port(name, 'gre', remote_ip,
local_ip=local_ip, key=key, ofport=ofport)
def add_vxlan_port(self, name, remote_ip,
local_ip=None, key=None, ofport=None):
+ """
+ Creates a VxLAN tunnel port.
+
+ See the description of ``add_tunnel_port()``.
+ """
self.add_tunnel_port(name, 'vxlan', remote_ip,
local_ip=local_ip, key=key, ofport=ofport)
def del_port(self, port_name):
+ """
+ Deletes a port on OVS instance.
+
+ This method is corresponding to the following ovs-vsctl command::
+
+ $ ovs-vsctl del-port <bridge> <port>
+ """
command = ovs_vsctl.VSCtlCommand('del-port', (self.br_name, port_name))
self.run_command([command])
@@ -396,6 +522,9 @@ class OVSBridge(object):
return None
def set_qos(self, port_name, type='linux-htb', max_rate=None, queues=None):
+ """
+ Sets a Qos rule and creates Queues on the given port.
+ """
queues = queues if queues else []
command_qos = ovs_vsctl.VSCtlCommand(
'set-qos',
@@ -409,6 +538,9 @@ class OVSBridge(object):
return None
def del_qos(self, port_name):
+ """
+ Deletes the Qos rule on the given port.
+ """
command = ovs_vsctl.VSCtlCommand(
'del-qos',
[port_name])
diff --git a/ryu/lib/ovs/vsctl.py b/ryu/lib/ovs/vsctl.py
index b18b5ef1..f3355a1c 100644
--- a/ryu/lib/ovs/vsctl.py
+++ b/ryu/lib/ovs/vsctl.py
@@ -14,6 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+"""
+``ovs-vsctl`` command like library to speak OVSDB protocol
+"""
from __future__ import print_function
@@ -53,9 +56,9 @@ def valid_ovsdb_addr(addr):
The valid formats are:
- - unix:file
- - tcp:ip:port
- - ssl:ip:port
+ - ``unix:file``
+ - ``tcp:ip:port``
+ - ``ssl:ip:port``
If ip is IPv6 address, wrap ip with brackets (e.g., ssl:[::1]:6640).
@@ -959,6 +962,34 @@ class _VSCtlTable(object):
class VSCtlCommand(StringifyMixin):
+ """
+ Class to describe artgumens similar to those of ``ovs-vsctl`` command.
+
+ ``command`` specifies the command of ``ovs-vsctl``.
+
+ ``args`` specifies a list or tuple of arguments for the given command.
+
+ ``options`` specifies a list or tuple of options for the given command.
+ Please note that NOT all options of ``ovs-vsctl`` are supported.
+ For example, ``--id`` option is not yet supported.
+ This class supports the followings.
+
+ ================= =========================================================
+ Option Description
+ ================= =========================================================
+ ``--may-exist`` Does nothing when the given port already exists.
+ The supported commands are ``add-port`` and
+ ``add-bond``.
+ ``--fake-iface`` Creates a port as a fake interface.
+ The supported command is ``add-bond``.
+ ``--must-exist`` Raises exception if the given port does not exist.
+ The supported command is ``del-port``.
+ ``--with-iface`` Takes effect to the interface which has the same name.
+ The supported command is ``del-port``.
+ ``--if-exists`` Ignores exception when not found.
+ The supported command is ``get``.
+ ================= =========================================================
+ """
def __init__(self, command, args=None, options=None):
super(VSCtlCommand, self).__init__()
@@ -978,6 +1009,13 @@ class VSCtlCommand(StringifyMixin):
class VSCtl(object):
+ """
+ A class to describe an Open vSwitch instance.
+
+ ``remote`` specifies the address of the OVS instance.
+ :py:mod:`ryu.lib.ovs.vsctl.valid_ovsdb_addr` is a convenient function to
+ validate this address.
+ """
def _reset(self):
self.schema_helper = None
@@ -1237,6 +1275,19 @@ class VSCtl(object):
self._do_main(commands)
def run_command(self, commands, timeout_sec=None, exception=None):
+ """
+ Executes the given commands and sends OVSDB messages.
+
+ ``commands`` must be a list of
+ :py:mod:`ryu.lib.ovs.vsctl.VSCtlCommand`.
+
+ If ``timeout_sec`` is specified, raises exception after the given
+ timeout [sec]. Additionally, if ``exception`` is specified, this
+ function will wraps exception using the given exception class.
+
+ Retruns ``None`` but fills ``result`` attribute for each command
+ instance.
+ """
if timeout_sec is None:
self._run_command(commands)
else: