diff options
Diffstat (limited to 'vswitches/ovs.py')
-rw-r--r-- | vswitches/ovs.py | 213 |
1 files changed, 205 insertions, 8 deletions
diff --git a/vswitches/ovs.py b/vswitches/ovs.py index 06dc7a1a..115ab19b 100644 --- a/vswitches/ovs.py +++ b/vswitches/ovs.py @@ -16,41 +16,83 @@ """ import logging +import os +import pexpect import re +import time + from conf import settings -from vswitches.vswitch import IVSwitch from src.ovs import OFBridge, flow_key, flow_match +from tools import tasks +from vswitches.vswitch import IVSwitch + +_OVS_VAR_DIR = settings.getValue('OVS_VAR_DIR') +_OVS_ETC_DIR = settings.getValue('OVS_ETC_DIR') -_VSWITCHD_CONST_ARGS = ['--', '--pidfile', '--log-file'] -class IVSwitchOvs(IVSwitch): +class IVSwitchOvs(IVSwitch, tasks.Process): """Open vSwitch base class implementation The method docstrings document only considerations specific to this implementation. For generic information of the nature of the methods, see the interface. """ + _logfile = os.path.join(settings.getValue('LOG_DIR'), settings.getValue('LOG_FILE_VSWITCHD')) + _ovsdb_pidfile_path = os.path.join(settings.getValue('LOG_DIR'), "ovsdb_pidfile.pid") + _vswitchd_pidfile_path = os.path.join(settings.getValue('LOG_DIR'), "vswitchd_pidfile.pid") + _proc_name = 'ovs-vswitchd' def __init__(self): """See IVswitch for general description """ - self._vswitchd = None self._logger = logging.getLogger(__name__) + self._expect = None + self._timeout = 30 self._bridges = {} - self._vswitchd_args = _VSWITCHD_CONST_ARGS + self._vswitchd_args = ['--pidfile=' + self._vswitchd_pidfile_path, + '--overwrite-pidfile', '--log-file=' + self._logfile] + self._cmd = [] + self._cmd_template = ['sudo', '-E', os.path.join(settings.getValue('OVS_DIR'), + 'vswitchd', 'ovs-vswitchd')] def start(self): - """See IVswitch for general description + """ Start ``ovsdb-server`` and ``ovs-vswitchd`` instance. + + :raises: pexpect.EOF, pexpect.TIMEOUT """ self._logger.info("Starting vswitchd...") - self._vswitchd.start() + + self._cmd = self._cmd_template + self._vswitchd_args + + # DB must be started before vswitchd + self._reset_ovsdb() + self._start_ovsdb() + + # DB must be up before vswitchd config is altered or vswitchd started + time.sleep(3) + + self.configure() + + try: + tasks.Process.start(self) + self.relinquish() + except (pexpect.EOF, pexpect.TIMEOUT) as exc: + logging.error("Exception during VSwitch start.") + self._kill_ovsdb() + raise exc + self._logger.info("Vswitchd...Started.") + def configure(self): + """ Configure vswitchd through ovsdb if needed + """ + pass + def stop(self): """See IVswitch for general description """ self._logger.info("Terminating vswitchd...") - self._vswitchd.kill() + self.kill() self._logger.info("Vswitchd...Terminated.") def add_switch(self, switch_name, params=None): @@ -153,6 +195,137 @@ class IVSwitchOvs(IVSwitch): cnt = 0 return cnt + def disable_stp(self, switch_name): + """ + Disable stp protocol on the bridge + :param switch_name: bridge to disable stp + :return: None + """ + bridge = self._bridges[switch_name] + bridge.set_stp(False) + self._logger.info('Sleeping for 50 secs to allow stp to stop.') + time.sleep(50) # needs time to disable + + def enable_stp(self, switch_name): + """ + Enable stp protocol on the bridge + :param switch_name: bridge to enable stp + :return: None + """ + bridge = self._bridges[switch_name] + bridge.set_stp(True) + self._logger.info('Sleeping for 50 secs to allow stp to start.') + time.sleep(50) # needs time to enable + + def disable_rstp(self, switch_name): + """ + Disable rstp on the bridge + :param switch_name: bridge to disable rstp + :return: None + """ + bridge = self._bridges[switch_name] + bridge.set_rstp(False) + self._logger.info('Sleeping for 15 secs to allow rstp to stop.') + time.sleep(15) # needs time to disable + + def enable_rstp(self, switch_name): + """ + Enable rstp on the bridge + :param switch_name: bridge to enable rstp + :return: None + """ + bridge = self._bridges[switch_name] + bridge.set_rstp(True) + self._logger.info('Sleeping for 15 secs to allow rstp to start.') + time.sleep(15) # needs time to enable + + def kill(self, signal='-15', sleep=10): + """Kill ``ovs-vswitchd`` and ``ovs-ovsdb`` instances if they are alive. + + :returns: None + """ + if os.path.isfile(self._vswitchd_pidfile_path): + self._logger.info('Killing ovs-vswitchd...') + with open(self._vswitchd_pidfile_path, "r") as pidfile: + vswitchd_pid = pidfile.read().strip() + tasks.terminate_task(vswitchd_pid, logger=self._logger) + + self._kill_ovsdb() # ovsdb must be killed after vswitchd + + # just for case, that sudo envelope has not been terminated yet + tasks.Process.kill(self, signal, sleep) + + # helper functions + + def _reset_ovsdb(self): + """Reset system for 'ovsdb'. + + :returns: None + """ + self._logger.info('Resetting system after last run...') + + tasks.run_task(['sudo', 'rm', '-rf', _OVS_VAR_DIR], self._logger) + tasks.run_task(['sudo', 'mkdir', '-p', _OVS_VAR_DIR], self._logger) + tasks.run_task(['sudo', 'rm', '-rf', _OVS_ETC_DIR], self._logger) + tasks.run_task(['sudo', 'mkdir', '-p', _OVS_ETC_DIR], self._logger) + + tasks.run_task(['sudo', 'rm', '-f', + os.path.join(_OVS_ETC_DIR, 'conf.db')], + self._logger) + + self._logger.info('System reset after last run.') + + def _start_ovsdb(self): + """Start ``ovsdb-server`` instance. + + :returns: None + """ + ovsdb_tool_bin = os.path.join( + settings.getValue('OVS_DIR'), 'ovsdb', 'ovsdb-tool') + tasks.run_task(['sudo', ovsdb_tool_bin, 'create', + os.path.join(_OVS_ETC_DIR, 'conf.db'), + os.path.join(settings.getValue('OVS_DIR'), 'vswitchd', + 'vswitch.ovsschema')], + self._logger, + 'Creating ovsdb configuration database...') + + ovsdb_server_bin = os.path.join( + settings.getValue('OVS_DIR'), 'ovsdb', 'ovsdb-server') + + tasks.run_background_task( + ['sudo', ovsdb_server_bin, + '--remote=punix:%s' % os.path.join(_OVS_VAR_DIR, 'db.sock'), + '--remote=db:Open_vSwitch,Open_vSwitch,manager_options', + '--pidfile=' + self._ovsdb_pidfile_path, '--overwrite-pidfile'], + self._logger, + 'Starting ovsdb-server...') + + def _kill_ovsdb(self): + """Kill ``ovsdb-server`` instance. + + :returns: None + """ + if os.path.isfile(self._ovsdb_pidfile_path): + with open(self._ovsdb_pidfile_path, "r") as pidfile: + ovsdb_pid = pidfile.read().strip() + + self._logger.info("Killing ovsdb with pid: " + ovsdb_pid) + + if ovsdb_pid: + tasks.terminate_task(ovsdb_pid, logger=self._logger) + + @staticmethod + def get_db_sock_path(): + """Method returns location of db.sock file + + :returns: path to db.sock file. + """ + return os.path.join(_OVS_VAR_DIR, 'db.sock') + + # + # validate methods required for integration testcases + # + def validate_add_switch(self, result, switch_name, params=None): """Validate - Create a new logical switch with no ports """ @@ -227,3 +400,27 @@ class IVSwitchOvs(IVSwitch): """ Validate call of flow dump """ return True + + def validate_disable_rstp(self, result, switch_name): + """ Validate rstp disable + """ + bridge = self._bridges[switch_name] + return 'rstp_enable : false' in ''.join(bridge.bridge_info()) + + def validate_enable_rstp(self, result, switch_name): + """ Validate rstp enable + """ + bridge = self._bridges[switch_name] + return 'rstp_enable : true' in ''.join(bridge.bridge_info()) + + def validate_disable_stp(self, result, switch_name): + """ Validate stp disable + """ + bridge = self._bridges[switch_name] + return 'stp_enable : false' in ''.join(bridge.bridge_info()) + + def validate_enable_stp(self, result, switch_name): + """ Validate stp enable + """ + bridge = self._bridges[switch_name] + return 'stp_enable : true' in ''.join(bridge.bridge_info()) |