# Copyright 2015-2016 Intel Corporation. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Wrapper for an OVS bridge for convenient use of ``ovs-vsctl`` and ``ovs-ofctl`` on it. Much of this code is based on ``ovs-lib.py`` from Open Stack: https://github.com/openstack/neutron/blob/6eac1dc99124ca024d6a69b3abfa3bc69c735667/neutron/agent/linux/ovs_lib.py """ import os import logging import string import re from tools import tasks from conf import settings _OVS_VSCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities', 'ovs-vsctl') _OVS_OFCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities', 'ovs-ofctl') _OVS_APPCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities', 'ovs-appctl') _OVS_BRIDGE_NAME = settings.getValue('VSWITCH_BRIDGE_NAME') _CACHE_FILE_NAME = '/tmp/vsperf_flows_cache' class OFBase(object): """Add/remove/show datapaths using ``ovs-ofctl``. """ def __init__(self, timeout=10): """Initialise logger. :param timeout: Timeout to be used for each command :returns: None """ self.logger = logging.getLogger(__name__) self.timeout = timeout # helpers def run_vsctl(self, args, check_error=False): """Run ``ovs-vsctl`` with supplied arguments. :param args: Arguments to pass to ``ovs-vsctl`` :param check_error: Throw exception on error :return: None """ cmd = ['sudo', _OVS_VSCTL_BIN, '--timeout', str(self.timeout)] + args return tasks.run_task( cmd, self.logger, 'Running ovs-vsctl...', check_error) def run_appctl(self, args, check_error=False): """Run ``ovs-appctl`` with supplied arguments. :param args: Arguments to pass to ``ovs-appctl`` :param check_error: Throw exception on error :return: None """ cmd = ['sudo', _OVS_APPCTL_BIN, '--timeout', str(self.timeout)] + args return tasks.run_task( cmd, self.logger, 'Running ovs-appctl...', check_error) # datapath management def add_br(self, br_name=_OVS_BRIDGE_NAME, params=None): """Add datapath. :param br_name: Name of bridge :return: Instance of :class OFBridge: """ if params is None: params = [] self.logger.debug('add bridge') self.run_vsctl(['add-br', br_name]+params) return OFBridge(br_name, self.timeout) def del_br(self, br_name=_OVS_BRIDGE_NAME): """Delete datapath. :param br_name: Name of bridge :return: None """ self.logger.debug('delete bridge') self.run_vsctl(['del-br', br_name]) # Route and ARP functions def add_route(self, network, destination): """Add route to tunneling routing table. :param network: Network :param destination: Gateway :return: None """ self.logger.debug('add ovs/route') self.run_appctl(['ovs/route/add', network, destination]) def set_tunnel_arp(self, ip_addr, mac_addr, br_name=_OVS_BRIDGE_NAME): """Add OVS arp entry for tunneling :param ip: IP of bridge :param mac_addr: MAC address of the bridge :param br_name: Name of the bridge :return: None """ self.logger.debug('tnl/arp/set') self.run_appctl(['tnl/arp/set', br_name, ip_addr, mac_addr]) class OFBridge(OFBase): """Control a bridge instance using ``ovs-vsctl`` and ``ovs-ofctl``. """ def __init__(self, br_name=_OVS_BRIDGE_NAME, timeout=10): """Initialise bridge. :param br_name: Bridge name :param timeout: Timeout to be used for each command :returns: None """ super(OFBridge, self).__init__(timeout) self.br_name = br_name self._ports = {} self._cache_file = None # context manager def __enter__(self): """Create datapath :returns: self """ return self def __exit__(self, type_, value, traceback): """Remove datapath. """ if not traceback: self.destroy() # helpers def run_ofctl(self, args, check_error=False, timeout=None): """Run ``ovs-ofctl`` with supplied arguments. :param a