Edward Haas has uploaded a new change for review. Change subject: net: Adding bond api with sysfs driver under link ......................................................................
net: Adding bond api with sysfs driver under link Change-Id: I75f4f6b370f29411158e288610a1677b52998546 Signed-off-by: Edward Haas <edwa...@redhat.com> --- A lib/vdsm/network/link/bond.py A tests/network/link_bond_test.py 2 files changed, 236 insertions(+), 0 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/28/62828/1 diff --git a/lib/vdsm/network/link/bond.py b/lib/vdsm/network/link/bond.py new file mode 100644 index 0000000..11498f8 --- /dev/null +++ b/lib/vdsm/network/link/bond.py @@ -0,0 +1,160 @@ +# 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 abc +import os +import six + +from . import iface + + +@six.add_metaclass(abc.ABCMeta) +class BondAPI(object): + """ + Bond driver interface. + """ + def __init__(self, name, slaves=(), options=None): + self._master = name + self._slaves = set(slaves) + self._options = options + if self.is_bond(): + self._import_existing() + + @abc.abstractmethod + def create(self): + pass + + @abc.abstractmethod + def destroy(self): + pass + + @abc.abstractmethod + def add_slaves(self, slaves): + pass + + @abc.abstractmethod + def del_slaves(self, slaves): + pass + + @abc.abstractmethod + def set_options(self, options): + pass + + @abc.abstractmethod + def is_bond(self): + pass + + @abc.abstractmethod + def active_slave(self): + pass + + @property + def master(self): + return self._master + + @property + def slaves(self): + return self._slaves + + @property + def options(self): + return self._options + + def up(self): + self._setlinks(up=True) + + def down(self): + self._setlinks(up=False) + + @abc.abstractmethod + def _import_existing(self): + pass + + def _setlinks(self, up): + setstate = iface.up if up else iface.down + setstate(self._master) + for slave in self._slaves: + setstate(slave) + + +class BondSysFS(BondAPI): + + BONDING_MASTERS = '/sys/class/net/bonding_masters' + BONDING_PATH = '/sys/class/net/%s/bonding' + BONDING_SLAVES = BONDING_PATH + '/slaves' + BONDING_ACTIVE_SLAVE = BONDING_PATH + '/active_slave' + BONDING_OPT = BONDING_PATH + '/%s' + + def __init__(self, name, slaves=(), options=None): + super(BondSysFS, self).__init__(name, slaves, options) + + def create(self): + with open(self.BONDING_MASTERS, 'w') as f: + f.write('+%s' % self._master) + if self._slaves: + self.add_slaves(self._slaves) + + def destroy(self): + with open(self.BONDING_MASTERS, 'w') as f: + f.write('-%s' % self._master) + + def add_slaves(self, slaves): + self._slaves |= set(slaves) + for slave in slaves: + iface.down(slave) + with open(self.BONDING_SLAVES % self._master, 'w') as f: + f.write('+%s' % slave) + + def del_slaves(self, slaves): + self._slaves -= set(slaves) + for slave in slaves: + iface.down(slave) + with open(self.BONDING_SLAVES % self._master, 'w') as f: + f.write('-%s' % slave) + + def set_options(self, options): + self._options.update(options) + for key, value in options: + with open(self.BONDING_OPT % (self._master, key), 'w') as f: + f.write(value) + + def is_bond(self): + return os.path.exists(self.BONDING_PATH % self._master) + + def active_slave(self): + with open(self.BONDING_ACTIVE_SLAVE % self._master) as f: + return f.readline().rstrip() + + def _import_existing(self): + with open(self.BONDING_SLAVES % self._master) as f: + self._slaves = set(f.readline().split()) + # TODO: Support options + self._options = None + + +# TODO: Use a configuration parameter to determine which driver to use. +def _bond_driver(): + """ + Return the bond driver implementation. + """ + return BondSysFS + + +Bond = _bond_driver() diff --git a/tests/network/link_bond_test.py b/tests/network/link_bond_test.py new file mode 100644 index 0000000..0e815d0 --- /dev/null +++ b/tests/network/link_bond_test.py @@ -0,0 +1,76 @@ +# 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 + +from contextlib import contextmanager + +from nose.plugins.attrib import attr + +from testlib import VdsmTestCase as TestCaseBase + +from .nettestlib import dummy_devices + +from vdsm.network.link import iface +from vdsm.network.link.bond import Bond +from vdsm.utils import random_iface_name + + +@attr(type='integration') +class LinkBondTests(TestCaseBase): + + def test_bond_without_slaves(self): + with bond_device() as bond: + self.assertFalse(iface.is_up(bond.master)) + + def test_bond_with_slaves(self): + with dummy_devices(2) as (nic1, nic2): + with bond_device() as bond: + bond.add_slaves((nic1, nic2)) + self.assertFalse(iface.is_up(bond.master)) + + def test_bond_devices_are_up(self): + with dummy_devices(2) as (nic1, nic2): + with bond_device() as bond: + bond.add_slaves((nic1, nic2)) + bond.up() + self.assertTrue(iface.is_up(nic1)) + self.assertTrue(iface.is_up(nic2)) + self.assertTrue(iface.is_up(bond.master)) + + def test_bond_exists(self): + with dummy_devices(2) as (nic1, nic2): + with bond_device() as _bond: + _bond.add_slaves((nic1, nic2)) + _bond.up() + + bond = Bond(_bond.master) + self.assertEqual(bond.slaves, set((nic1, nic2))) + # TODO: Support options + self.assertEqual(bond.options, None) + + +@contextmanager +def bond_device(prefix='bond_', max_length=11): + bond_name = random_iface_name(prefix, max_length) + bond = Bond(bond_name) + bond.create() + try: + yield bond + finally: + bond.destroy() -- To view, visit https://gerrit.ovirt.org/62828 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I75f4f6b370f29411158e288610a1677b52998546 Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Edward Haas <edwa...@redhat.com> _______________________________________________ vdsm-patches mailing list vdsm-patches@lists.fedorahosted.org https://lists.fedorahosted.org/admin/lists/vdsm-patches@lists.fedorahosted.org