Change in vdsm[master]: net: native ovs [1]

phoracek at redhat.com phoracek at redhat.com
Wed Mar 16 15:42:30 UTC 2016


Petr Horáček has uploaded a new change for review.

Change subject: net: native ovs [1]
......................................................................

net: native ovs [1]

Basic OVS implementation.

Change-Id: I6d18b7d3e90902d29a2fdef246972a9fb1c705f1
Signed-off-by: Petr Horáček <phoracek at redhat.com>
---
M lib/vdsm/network/api.py
A lib/vdsm/network/ovs_switch/Makefile.am
A lib/vdsm/network/ovs_switch/__init__.py
A lib/vdsm/network/ovs_switch/libvirt.py
A lib/vdsm/network/ovs_switch/ovs.py
A lib/vdsm/network/ovs_switch/switch.py
A lib/vdsm/network/ovs_switch/validator.py
7 files changed, 353 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/21/54821/1

diff --git a/lib/vdsm/network/api.py b/lib/vdsm/network/api.py
index 74557fa..e5c4a4f 100644
--- a/lib/vdsm/network/api.py
+++ b/lib/vdsm/network/api.py
@@ -33,15 +33,20 @@
 from vdsm import constants
 from vdsm import hooks
 from vdsm import netconfpersistence
+"""legacy
 from vdsm.netinfo.cache import (libvirtNets2vdsm, get as netinfo_get,
                                 CachingNetInfo)
 from vdsm.netinfo import networks as netinfo_networks
+"""
 from vdsm import udevadm
 from vdsm import utils
 from vdsm import ipwrapper
 
 from . canonicalize import canonicalize_networks
+"""legacy
 from . import legacy_switch
+"""
+from .ovs_switch import switch as ovs_switch
 from . import errors as ne
 from .configurators import RollbackIncomplete
 from .errors import ConfigNetworkError
@@ -243,17 +248,23 @@
     # TODO: Add canonicalize_bondings(bondings)
 
     logging.debug('Validating configuration')
+    """legacy
     legacy_switch.validate_network_setup(networks, bondings)
+    """
+    ovs_switch.validate_network_setup(networks, bondings)
 
     bondings, networks, options = _apply_hook(bondings, networks, options)
 
+    """legacy
     libvirt_nets = netinfo_networks()
     _netinfo = CachingNetInfo(_netinfo=netinfo_get(
         libvirtNets2vdsm(libvirt_nets)))
+    """
 
     logging.debug('Applying...')
     in_rollback = options.get('_inRollback', False)
     with _rollback():
+        """legacy
         with legacy_switch.ConfiguratorClass(in_rollback) as configurator:
             # from this point forward, any exception thrown will be handled by
             # Configurator.__exit__.
@@ -266,6 +277,10 @@
 
             legacy_switch.add_missing_networks(configurator, networks,
                                                bondings, _netinfo)
+        """
+        with ovs_switch.OvsManager(in_rollback) as manager:
+            ovs_switch.setup(networks, bondings, in_rollback,
+                             manager.running_config)
 
             _check_connectivity(networks, bondings, options)
 
diff --git a/lib/vdsm/network/ovs_switch/Makefile.am b/lib/vdsm/network/ovs_switch/Makefile.am
new file mode 100644
index 0000000..ca1a4b0
--- /dev/null
+++ b/lib/vdsm/network/ovs_switch/Makefile.am
@@ -0,0 +1,28 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+include $(top_srcdir)/build-aux/Makefile.subs
+
+vdsmnetworkovsswitchdir = $(vdsmpylibdir)/network/ovs_switch
+
+dist_vdsmnetworkovsswitch_PYTHON = \
+	__init__.py \
+	ovs.py \
+	switch.py \
+	$(NULL)
diff --git a/lib/vdsm/network/ovs_switch/__init__.py b/lib/vdsm/network/ovs_switch/__init__.py
new file mode 100644
index 0000000..4a67f47
--- /dev/null
+++ b/lib/vdsm/network/ovs_switch/__init__.py
@@ -0,0 +1,19 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from __future__ import absolute_import
diff --git a/lib/vdsm/network/ovs_switch/libvirt.py b/lib/vdsm/network/ovs_switch/libvirt.py
new file mode 100644
index 0000000..ac27cc0
--- /dev/null
+++ b/lib/vdsm/network/ovs_switch/libvirt.py
@@ -0,0 +1,20 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+from __future__ import absolute_import
diff --git a/lib/vdsm/network/ovs_switch/ovs.py b/lib/vdsm/network/ovs_switch/ovs.py
new file mode 100644
index 0000000..ac27cc0
--- /dev/null
+++ b/lib/vdsm/network/ovs_switch/ovs.py
@@ -0,0 +1,20 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+from __future__ import absolute_import
diff --git a/lib/vdsm/network/ovs_switch/switch.py b/lib/vdsm/network/ovs_switch/switch.py
new file mode 100644
index 0000000..e94f075
--- /dev/null
+++ b/lib/vdsm/network/ovs_switch/switch.py
@@ -0,0 +1,146 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+from __future__ import absolute_import
+import logging
+
+import six
+
+from vdsm.netconfpersistence import RunningConfig
+
+from . import libvirt as _libvirt
+from . import ovs as _ovs
+from . import validator
+
+
+class RollbackIncomplete(Exception):
+    """
+    This exception is raised in order to signal API.Global that a call to
+    setupNetworks has failed and there are leftovers that need to be cleaned
+    up.
+    """
+    pass
+
+
+class RollbackManager(object):  # TODO inherit interface
+    def __init__(self, in_rollback):
+        self.in_rollback = in_rollback
+
+    def __enter__(self):
+        self.running_config = RunningConfig()
+        return self
+
+    def __exit__(self, type, value, traceback):
+        if type is None:
+            self.commit()
+        elif self._in_rollback:
+            # If we failed the rollback transaction, the networking system
+            # is in no good state and we fail hard
+            logging.error('Failed rollback transaction last known good '
+                          'network.', exc_info=(type, value, traceback))
+        else:
+            leftover = self.rollback()
+            if leftover:
+                raise RollbackIncomplete(leftover, type, value)
+
+    def rollback(self):
+        """
+        Returns None when all the nets were successfully rolled back, a
+        vdsm.netoconfpersistence.Config object with the not yet rolled back
+        networks and bonds.
+        """
+        # self.runningConfig will have all the changes that were applied before
+        # we needed to rollback.
+        return RunningConfig().diffFrom(self.runningConfig)
+
+    def commit(self):
+        raise NotImplementedError
+
+
+class OvsManager(RollbackManager):
+    def commit(self):
+        self.running_config.save()
+
+
+def setup(nets, bonds, in_rollback, running_config):
+    nets_to_be_added, nets_to_be_removed = _filter_nets(nets, running_config)
+    bonds_to_be_added, bonds_to_be_removed = _filter_bonds(bonds,
+                                                           running_config)
+
+    _ovs.remove(nets_to_be_removed, bonds_to_be_removed, running_config)
+    _libvirt.remove(nets_to_be_removed)
+    _ovs.add(nets_to_be_added, bonds_to_be_added, running_config)
+    _libvirt.add(nets_to_be_added, running_config)
+    _set_devices_up(nets_to_be_added, bonds_to_be_added)
+
+
+def _filter_nets(nets, running_config):
+    nets_to_be_removed = set()
+    nets_to_be_added = {}
+
+    for net, attrs in six.iteritems(nets):
+        if ('remove' not in attrs and
+                attrs != running_config.networks.get(net)):
+            nets_to_be_added[net] = attrs
+        if 'remove' in attrs or (
+                (net in running_config.networks and
+                 attrs != running_config.networks.get(net))):
+            nets_to_be_removed.add(net)
+
+    return nets_to_be_added, nets_to_be_removed
+
+
+def _filter_bonds(bonds, running_config):
+    bonds_to_be_removed = set()
+    bonds_to_be_added = {}
+
+    for bond, attrs in six.iteritems(bonds):
+        if ('remove' not in attrs and
+                attrs != running_config.bonds.get(bond)):
+            bonds_to_be_added[bond] = attrs
+        if 'remove' in attrs:
+            bonds_to_be_removed.add(bond)
+
+    return bonds_to_be_added, bonds_to_be_removed
+
+
+def _set_devices_up(nets, bonds):
+    devices = set()
+    for net, attrs in six.iteritems(nets):
+        if 'remove' not in attrs:
+            if 'vlan' in attrs:
+                devices.add(net)
+            if 'nic' in attrs or 'bond' in attrs:
+                devices.add(attrs.get('nic') or attrs.get('bond'))
+    for bond, attrs in six.iteritems(bonds):
+        if 'remove' not in attrs:
+            devices.add(bond)
+            devices.update(attrs['nics'])
+    if ovs_bridge_exists(BRIDGE_NAME):
+        devices.add(BRIDGE_NAME)
+    for device in devices:
+        linkSet(device, ['up'])
+
+
+def validate_network_setup(nets, bonds, running_config, netinfo):
+    for net, attrs in six.iteritems(nets):
+        validator.validate_net_configuration(net, attrs, running_config,
+                                             netinfo)
+    for _, attrs in six.iteritems(bonds):
+        validator.validate_bond_configuration(attrs, netinfo)
diff --git a/lib/vdsm/network/ovs_switch/validator.py b/lib/vdsm/network/ovs_switch/validator.py
new file mode 100644
index 0000000..16f44c2
--- /dev/null
+++ b/lib/vdsm/network/ovs_switch/validator.py
@@ -0,0 +1,105 @@
+# Copyright 2015-2016 Red Hat, Inc.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from __future__ import absolute_import
+
+import six
+
+from vdsm.network import errors as ne
+from vdsm.network.errors import ConfigNetworkError
+
+from .utils import get_bond_options, is_ovs_bond, rget, iter_ovs_nets
+
+VALID_MODES = frozenset(['active-backup', 'balance-tcp', 'balance-slb'])
+VALID_LACP = frozenset(['active', 'passive', 'off'])
+
+
+def _get_untagged_net(running_config):
+    for net, attrs in iter_ovs_nets(running_config.networks):
+        if 'vlan' not in attrs:
+            return net
+    return None
+
+
+def validate_net_configuration(net, attrs, running_config, netinfo):
+    nic = attrs.get('nic')
+    bond = attrs.get('bonding')
+    vlan = attrs.get('vlan')
+    bridged = attrs.get('bridged', True)
+    stp = attrs.get('stp', False)
+
+    if not bridged:
+        raise ConfigNetworkError(
+            ne.ERR_BAD_PARAMS, 'OVS does not support bridgeless networks')
+    if bond in running_config.bonds:
+        if not is_ovs_bond(running_config.bonds[bond]):
+            raise ConfigNetworkError(
+                ne.ERR_BAD_BONDING, '%s is not OVS bonding' % bond)
+    if nic is not None and nic not in netinfo.nics:
+        raise ConfigNetworkError(
+            ne.ERR_BAD_NIC, 'Nic %s does not exist' % nic)
+    if vlan is not None and bond is None and nic is None:
+        raise ConfigNetworkError(
+            ne.ERR_BAD_VLAN, 'You can not create a nicless/bondless vlan')
+
+    for existing_net, existing_attrs in six.iteritems(running_config.networks):
+        if (existing_net != net and
+                existing_attrs.get('nic') == nic and
+                existing_attrs.get('bond') == bond and
+                existing_attrs.get('vlan') == vlan):
+            raise ConfigNetworkError(
+                ne.ERR_BAD_PARAMS, '%s is already used by network %s' %
+                                    ((nic or bond), existing_net))
+    if vlan is None:
+        untagged_net = _get_untagged_net(running_config)
+        if untagged_net not in (None, net):
+            raise ConfigNetworkError(
+                ne.ERR_BAD_VLAN,
+                'Untagged network already defined with name %s' % untagged_net)
+        if rget(attrs, ('custom', 'ovs_aa_sid')) is not None:
+            raise ConfigNetworkError(
+                ne.ERR_BAD_PARAMS,
+                'Cannot define aa-mapping on untagged network')
+    if stp and vlan is not None:
+        raise ConfigNetworkError(
+            ne.ERR_BAD_PARAMS, 'STP could be set only on untagged networks')
+
+
+def validate_bond_configuration(attrs, netinfo):
+    nics = attrs.get('nics')
+    bond_options = get_bond_options(attrs.get('options'))
+
+    if nics is None or len(attrs.get('nics')) < 2:
+        raise ConfigNetworkError(
+            ne.ERR_BAD_BONDING,
+            'You have to define at least 2 slaves for OVS bonding')
+    for nic in nics:
+        if nic not in netinfo.nics:
+            raise ConfigNetworkError(
+                ne.ERR_BAD_NIC, 'Nic %s does not exist' % nic)
+
+    mode = rget(bond_options, ('custom', 'ovs_mode')) or 'active-backup'
+    lacp = rget(bond_options, ('custom', 'ovs_lacp')) or 'off'
+    if mode:
+        if mode not in VALID_MODES:
+            raise ConfigNetworkError(
+                ne.ERR_BAD_PARAMS, '%s is not valid ovs bond mode' % mode)
+    if lacp:
+        if lacp not in VALID_LACP:
+            raise ConfigNetworkError(
+                ne.ERR_BAD_PARAMS, '%s is not valid ovs lacp value' % lacp)


-- 
To view, visit https://gerrit.ovirt.org/54821
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I6d18b7d3e90902d29a2fdef246972a9fb1c705f1
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Petr Horáček <phoracek at redhat.com>


More information about the vdsm-patches mailing list