Tap Mirror OVS driver
Related-Bug: #2015471 Change-Id: I9a80fd7a6c3b782454047b6295e51cc549842f84
This commit is contained in:
parent
6e28f4bb85
commit
1037b31692
|
@ -27,6 +27,7 @@ from neutron_lib import constants
|
|||
from neutron_lib import context as neutron_context
|
||||
from neutron_lib import rpc as n_rpc
|
||||
from oslo_config import cfg
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging as messaging
|
||||
from oslo_service import service
|
||||
|
@ -72,6 +73,12 @@ class TaasPluginApi(api.TaasPluginApiMixin):
|
|||
cctxt.cast(context, 'set_tap_flow_status', msg=msg, status=status,
|
||||
host=host)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def set_tap_mirror_status(self, msg, status, host):
|
||||
LOG.debug("In RPC Call for set Tap Mirror status")
|
||||
# TODO(lajoskatona): We can have a status field to indicate that the
|
||||
# Neutron port is UP, is it useful?
|
||||
|
||||
|
||||
class TaasAgentRpcCallback(api.TaasAgentRpcCallbackMixin):
|
||||
|
||||
|
@ -110,6 +117,16 @@ class TaasAgentRpcCallback(api.TaasAgentRpcCallbackMixin):
|
|||
'set_status_func_name': 'set_tap_flow_status',
|
||||
'fail_status': constants.PENDING_DELETE,
|
||||
'succ_status': constants.INACTIVE},
|
||||
'create_tap_mirror': {
|
||||
'msg_name': 'tap_mirror',
|
||||
'set_status_func_name': 'set_tap_mirror_status',
|
||||
'fail_status': constants.ERROR,
|
||||
'succ_status': constants.ACTIVE},
|
||||
'delete_tap_mirror': {
|
||||
'msg_name': 'tap_mirror',
|
||||
'set_status_func_name': 'set_tap_mirror_status',
|
||||
'fail_status': constants.PENDING_DELETE,
|
||||
'succ_status': constants.INACTIVE},
|
||||
'periodic_tasks': {
|
||||
'msg_name': 'periodic_tasks',
|
||||
}
|
||||
|
@ -212,6 +229,39 @@ class TaasAgentRpcCallback(api.TaasAgentRpcCallbackMixin):
|
|||
tap_flow_msg,
|
||||
'delete_tap_flow')
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create_tap_mirror(self, context, tap_mirror_msg, host):
|
||||
"""Handle Rpc from plugin to create a tap_mirror."""
|
||||
if not self._driver_and_host_verification(
|
||||
host, tap_mirror_msg['port']):
|
||||
LOG.debug("RPC Call for Create Tap Mirror. Either Host value [%s]"
|
||||
"(received in RPC) doesn't match the host value "
|
||||
"stored in agent [%s], or incompatible driver type. "
|
||||
"Ignoring the message.", host, self.conf.host)
|
||||
return
|
||||
|
||||
return self._invoke_driver_for_plugin_api(
|
||||
context,
|
||||
tap_mirror_msg,
|
||||
'create_tap_mirror')
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete_tap_mirror(self, context, tap_mirror_msg, host):
|
||||
"""...."""
|
||||
if not self._driver_and_host_verification(host,
|
||||
tap_mirror_msg['port']):
|
||||
LOG.debug("RPC Call for Delete Tap Mirror. Either Host value [%s]"
|
||||
"(received in RPC) doesn't match the host value "
|
||||
"stored in agent [%s], or incompatible driver type. "
|
||||
"Ignoring the message." % (host, self.conf.host))
|
||||
return
|
||||
LOG.debug("In RPC Call for Delete Tap Mirror: MSG=%s", tap_mirror_msg)
|
||||
|
||||
return self._invoke_driver_for_plugin_api(
|
||||
context,
|
||||
tap_mirror_msg,
|
||||
'delete_tap_mirror')
|
||||
|
||||
def _taas_rpc_setup(self):
|
||||
# setup RPC to msg taas plugin
|
||||
self.taas_plugin_rpc = TaasPluginApi(
|
||||
|
|
|
@ -57,3 +57,11 @@ class TaasAgentRpcCallbackMixin(object):
|
|||
def delete_tap_flow(self, context, tap_flow_msg, host):
|
||||
"""Handle RPC cast from plugin to delete a tap flow"""
|
||||
pass
|
||||
|
||||
def create_tap_mirror(self, context, tap_mirror_msg, host):
|
||||
"""Handle RPC cast from plugin to create a Tap Mirror."""
|
||||
pass
|
||||
|
||||
def delete_tap_mirror(self, context, tap_mirror_msg, host):
|
||||
"""Handle RPC cast from plugin to delete a Tap Mirror."""
|
||||
pass
|
||||
|
|
|
@ -13,10 +13,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
|
||||
from neutron.agent.common import ovs_lib
|
||||
from neutron.agent.linux import utils
|
||||
from neutron.conf.agent import common
|
||||
from neutron.conf.plugins.ml2.drivers import ovs_conf
|
||||
from neutron_lib.plugins.ml2 import ovs_constants as n_ovs_consts
|
||||
|
||||
from neutron_taas.services.taas.agents.extensions import taas as taas_base
|
||||
|
@ -46,6 +48,7 @@ class OvsTaasDriver(taas_base.TaasAgentDriver):
|
|||
LOG.debug("Initializing Taas OVS Driver")
|
||||
self.agent_api = None
|
||||
self.root_helper = common.get_root_helper(cfg.CONF)
|
||||
ovs_conf.register_ovs_agent_opts(cfg.CONF)
|
||||
self.datapath_type = cfg.CONF.OVS.datapath_type
|
||||
self.tunnel_types = cfg.CONF.AGENT.tunnel_types
|
||||
|
||||
|
@ -577,3 +580,105 @@ class OvsTaasDriver(taas_base.TaasAgentDriver):
|
|||
dl_vlan=vlan_id,
|
||||
dl_dst=("01:00:00:00:00:00/"
|
||||
"01:00:00:00:00:00"))
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create_tap_mirror(self, tap_mirror_msg):
|
||||
source_port = tap_mirror_msg['port']
|
||||
tap_mirror = tap_mirror_msg['tap_mirror']
|
||||
|
||||
type = ''
|
||||
patch_int_tap_id = self.int_br.get_port_ofport('patch-int-tap')
|
||||
patch_tap_int_id = self.tap_br.get_port_ofport('patch-tap-int')
|
||||
|
||||
# Get OVS port id for tap flow port
|
||||
ovs_port = self.int_br.get_vif_port_by_id(source_port['id'])
|
||||
ovs_port_id = ovs_port.ofport
|
||||
|
||||
options = collections.OrderedDict()
|
||||
options['remote_ip'] = tap_mirror['remote_ip']
|
||||
if 'erspan' in tap_mirror['mirror_type']:
|
||||
type = 'erspan'
|
||||
options['erspan_ver'] = "1"
|
||||
options['erspan_idx'] = ""
|
||||
options['key'] = ""
|
||||
else:
|
||||
type = 'gre'
|
||||
directions = tap_mirror['directions']
|
||||
|
||||
for direction, tunnel_id in directions.items():
|
||||
options['erspan_idx'] = str(tunnel_id)
|
||||
# Note(lajoskatona): this is treated as hexa, so
|
||||
# spanId will be d102, and Index will be d258 in the packet.
|
||||
# As OVN doesn't care about this let's have OVS driver the same
|
||||
# behaviour.
|
||||
options['key'] = str(tunnel_id)
|
||||
port_name = 'tm_%s_%s' % (direction.lower(),
|
||||
tap_mirror['id'][0:6])
|
||||
attrs = [('type', type),
|
||||
('options', options)]
|
||||
mirror_of_port = self.tap_br.add_port(port_name, *attrs)
|
||||
|
||||
if direction == 'IN':
|
||||
self.tap_br.add_flow(table=taas_ovs_consts.TAAS_RECV_LOC,
|
||||
priority=20,
|
||||
dl_dst=source_port['mac_address'],
|
||||
actions="output:%s" % str(mirror_of_port))
|
||||
self.int_br.add_flow(
|
||||
table=0,
|
||||
priority=20,
|
||||
dl_dst=source_port['mac_address'],
|
||||
actions="output:%s,resubmit(,%s)" %
|
||||
(str(patch_int_tap_id),
|
||||
str(n_ovs_consts.PACKET_RATE_LIMIT)))
|
||||
if direction == 'OUT':
|
||||
self.tap_br.add_flow(table=taas_ovs_consts.TAAS_RECV_LOC,
|
||||
priority=20,
|
||||
dl_src=source_port['mac_address'],
|
||||
actions="output:%s" % str(mirror_of_port))
|
||||
self.int_br.add_flow(
|
||||
table=0,
|
||||
priority=20,
|
||||
in_port=ovs_port_id,
|
||||
actions="output:%s,resubmit(,%s)" %
|
||||
(str(patch_int_tap_id),
|
||||
str(n_ovs_consts.PACKET_RATE_LIMIT)))
|
||||
|
||||
# Add flow(s) in br-tap
|
||||
self.tap_br.add_flow(table=taas_ovs_consts.TAAS_RECV_LOC,
|
||||
priority=1,
|
||||
dl_dst=source_port['mac_address'],
|
||||
actions="output:in_port")
|
||||
|
||||
self.tap_br.add_flow(table=taas_ovs_consts.TAAS_RECV_REM,
|
||||
priority=1,
|
||||
dl_dst=source_port['mac_address'],
|
||||
actions="output:%s" % str(patch_tap_int_id))
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete_tap_mirror(self, tap_mirror_msg):
|
||||
source_port = tap_mirror_msg['port']
|
||||
tap_mirror = tap_mirror_msg['tap_mirror']
|
||||
directions = tap_mirror['directions']
|
||||
|
||||
# Get OVS port id for tap flow port
|
||||
ovs_port = self.int_br.get_vif_port_by_id(source_port['id'])
|
||||
ovs_port_id = ovs_port.ofport
|
||||
|
||||
self.tap_br.delete_flows(table=taas_ovs_consts.TAAS_RECV_REM,
|
||||
dl_dst=source_port['mac_address'])
|
||||
self.tap_br.delete_flows(table=taas_ovs_consts.TAAS_RECV_LOC,
|
||||
dl_dst=source_port['mac_address'])
|
||||
|
||||
for direction, tunnel_id in directions.items():
|
||||
if direction == 'IN':
|
||||
self.int_br.delete_flows(table=0,
|
||||
dl_dst=source_port['mac_address'])
|
||||
self.tap_br.delete_flows(table=taas_ovs_consts.TAAS_RECV_LOC,
|
||||
dl_dst=source_port['mac_address'])
|
||||
if direction == 'OUT':
|
||||
self.int_br.delete_flows(table=0, in_port=ovs_port_id)
|
||||
self.tap_br.delete_flows(table=taas_ovs_consts.TAAS_RECV_LOC,
|
||||
dl_src=source_port['mac_address'])
|
||||
port_name = 'tm_%s_%s' % (direction.lower(),
|
||||
tap_mirror['id'][0:6])
|
||||
self.tap_br.delete_port(port_name)
|
||||
|
|
|
@ -55,3 +55,19 @@ class TaasBaseDriver(object, metaclass=abc.ABCMeta):
|
|||
@abc.abstractmethod
|
||||
def delete_tap_flow_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_tap_mirror_precommit(self, context):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_tap_mirror_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_tap_mirror_precommit(self, context):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_tap_mirror_postcommit(self, context):
|
||||
pass
|
||||
|
|
|
@ -65,3 +65,14 @@ class TapFlowContext(ServiceDriverContext):
|
|||
@property
|
||||
def tap_flow(self):
|
||||
return self._tap_flow
|
||||
|
||||
|
||||
class TapMirrorContext(ServiceDriverContext):
|
||||
|
||||
def __init__(self, service_plugin, plugin_context, tap_mirror):
|
||||
super().__init__(service_plugin, plugin_context)
|
||||
self._tap_mirror = tap_mirror
|
||||
|
||||
@property
|
||||
def tap_mirror(self):
|
||||
return self._tap_mirror
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# under the License.
|
||||
|
||||
from neutron_lib import rpc as n_rpc
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging as messaging
|
||||
|
||||
|
@ -60,3 +61,15 @@ class TaasAgentApi(object):
|
|||
cctxt = self.client.prepare(fanout=True)
|
||||
cctxt.cast(context, 'delete_tap_flow', tap_flow_msg=tap_flow_msg,
|
||||
host=host)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create_tap_mirror(self, context, tap_mirror_msg, host):
|
||||
cctxt = self.client.prepare(fanout=True)
|
||||
cctxt.cast(context, 'create_tap_mirror', tap_mirror_msg=tap_mirror_msg,
|
||||
host=host)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete_tap_mirror(self, context, tap_mirror_msg, host):
|
||||
cctxt = self.client.prepare(fanout=True)
|
||||
cctxt.cast(context, 'delete_tap_mirror', tap_mirror_msg=tap_mirror_msg,
|
||||
host=host)
|
||||
|
|
|
@ -30,6 +30,7 @@ from neutron_taas.services.taas.service_drivers import taas_agent_api
|
|||
from neutron_taas.services.taas import taas_plugin
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
|
@ -328,3 +329,53 @@ class TaasRpcDriver(service_drivers.TaasBaseDriver):
|
|||
|
||||
def delete_tap_flow_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create_tap_mirror_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create_tap_mirror_postcommit(self, context):
|
||||
"""Send Tap Mirror creation RPC message to agent.
|
||||
|
||||
This RPC message includes ....
|
||||
"""
|
||||
# Get taas id associated with the Tap Service
|
||||
tm = context.tap_mirror
|
||||
port = self.service_plugin.get_port_details(context._plugin_context,
|
||||
tm['port_id'])
|
||||
host = port['binding:host_id']
|
||||
|
||||
rpc_msg = {'tap_mirror': tm,
|
||||
'port': port}
|
||||
|
||||
self.agent_rpc.create_tap_mirror(context._plugin_context,
|
||||
rpc_msg, host)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete_tap_mirror_precommit(self, context):
|
||||
"""Send Tap Mirror deletion RPC message to agent.
|
||||
|
||||
This RPC message includes .....
|
||||
"""
|
||||
tm = context.tap_mirror
|
||||
|
||||
try:
|
||||
port = self.service_plugin.get_port_details(
|
||||
context._plugin_context,
|
||||
tm['port_id'])
|
||||
host = port['binding:host_id']
|
||||
except n_exc.PortNotFound:
|
||||
# if not found, we just pass to None
|
||||
port = None
|
||||
host = None
|
||||
|
||||
rpc_msg = {'tap_mirror': tm,
|
||||
'port': port}
|
||||
|
||||
self.agent_rpc.delete_tap_mirror(context._plugin_context,
|
||||
rpc_msg, host)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete_tap_mirror_postcommit(self, context):
|
||||
pass
|
||||
|
|
|
@ -23,9 +23,12 @@ from neutron_lib.exceptions import taas as taas_exc
|
|||
from neutron_taas.common import constants as taas_consts
|
||||
from neutron_taas.db import tap_mirror_db
|
||||
from neutron_taas.extensions import _tap_mirror as t_m_api_def
|
||||
from neutron_taas.services.taas.service_drivers import (service_driver_context
|
||||
as sd_context)
|
||||
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -82,11 +85,22 @@ class TapMirrorPlugin(tap_mirror_db.Taas_mirror_db_Mixin):
|
|||
LOG.debug("Host on which the port is created = %s" % host)
|
||||
else:
|
||||
LOG.debug("Host could not be found, Port Binding disbaled!")
|
||||
# Fail here? Is it a valid usecase to create a mirror for a
|
||||
# port that is not bound?
|
||||
|
||||
with db_api.CONTEXT_WRITER.using(context):
|
||||
self._validate_tap_tunnel_id(context, t_m['directions'])
|
||||
tm = super().create_tap_mirror(context, tap_mirror)
|
||||
# Precommit phase, is it necessary? tunnel id check should be in
|
||||
# it....
|
||||
driver_context = sd_context.TapMirrorContext(self, context, tm)
|
||||
self.driver.create_tap_mirror_precommit(driver_context)
|
||||
|
||||
# Postcommit phase, do the backend stuff, or revert.
|
||||
try:
|
||||
self.driver.create_tap_mirror_postcommit(driver_context)
|
||||
except Exception:
|
||||
pass
|
||||
return tm
|
||||
|
||||
def _validate_tap_tunnel_id(self, context, mirror_directions):
|
||||
|
@ -104,9 +118,22 @@ class TapMirrorPlugin(tap_mirror_db.Taas_mirror_db_Mixin):
|
|||
|
||||
if tm:
|
||||
with db_api.CONTEXT_WRITER.using(context):
|
||||
# Precommit phase
|
||||
driver_context = sd_context.TapMirrorContext(
|
||||
self, context, tm)
|
||||
self.driver.delete_tap_mirror_precommit(driver_context)
|
||||
|
||||
# check if tunnel id was really deleted
|
||||
super().delete_tap_mirror(context, id)
|
||||
|
||||
# Postcommit phase, do the backend stuff, or revert.
|
||||
try:
|
||||
self.driver.delete_tap_mirror_postcommit(driver_context)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error("Failed to delete Tap Mirror on driver. "
|
||||
"tap_mirror: %s", id)
|
||||
|
||||
@registry.receives(resources.PORT, [events.PRECOMMIT_DELETE])
|
||||
@log_helpers.log_method_call
|
||||
def handle_delete_port(self, resource, event, trigger, payload):
|
||||
|
|
|
@ -11,8 +11,79 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
from oslotest import base
|
||||
|
||||
|
||||
FAKE_PORT_PARAMS = {
|
||||
'mac': '52:54:00:12:35:02', 'pci_slot': 3, 'vf_index': '89',
|
||||
'pf_device': 'net_enp0s3_52_54_00_12_35_02', 'src_vlans': '20'}
|
||||
|
||||
FAKE_TAP_SERVICE = {
|
||||
'taas_id': '1234',
|
||||
'port': {
|
||||
'id': 'fake_1',
|
||||
'mac_address': "52:54:00:12:35:02",
|
||||
'binding:profile': {'pci_slot': 3},
|
||||
'binding:vif_details': {'vlan': '20'}
|
||||
}
|
||||
}
|
||||
|
||||
FAKE_OF_PORT = {
|
||||
'port_name': 'tap4321',
|
||||
'ofport': 12,
|
||||
}
|
||||
FAKE_PORT_DICT = {
|
||||
FAKE_OF_PORT['port_name']: 4
|
||||
}
|
||||
FAKE_TAP_SERVICE_OVS = {
|
||||
'taas_id': 4321,
|
||||
'port': {
|
||||
'id': 'fake_2',
|
||||
'mac_address': "fa:16:3e:33:0e:d4",
|
||||
'binding:profile': {},
|
||||
'binding:vif_details': {
|
||||
'connectivity': 'l2',
|
||||
'port_filter': True,
|
||||
'ovs_hybrid_plug': False,
|
||||
'datapath_type': 'system',
|
||||
'bridge_name': 'br-int'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FAKE_TAP_FLOW = {
|
||||
'taas_id': FAKE_TAP_SERVICE_OVS['taas_id'],
|
||||
'port': FAKE_TAP_SERVICE['port'],
|
||||
'port_mac': 'fa:16:3e:5c:67:6a',
|
||||
'ts_port': FAKE_TAP_SERVICE['port'],
|
||||
'source_vlans_list': ['4-6', '8-10', '15-18,20'],
|
||||
'vlan_filter_list': '1-5,9,18,20,27-30,4000-4095',
|
||||
'tap_flow': {
|
||||
'direction': 'IN', 'vlan_filter': '20'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FAKE_TAP_MIRROR_OUT = {
|
||||
'tap_mirror': {
|
||||
'id': 'mirror_uuid',
|
||||
'port_id': 'port_uuid',
|
||||
'directions': {'OUT': '102'},
|
||||
'remote_ip': '100.109.0.48',
|
||||
'mirror_type': 'gre',
|
||||
},
|
||||
'port': {
|
||||
'id': 'port_uuid',
|
||||
'mac_address': 'fa:16:3e:69:0e:f3',
|
||||
}
|
||||
}
|
||||
|
||||
FAKE_TAP_MIRROR_IN = copy.deepcopy(FAKE_TAP_MIRROR_OUT)
|
||||
FAKE_TAP_MIRROR_IN['tap_mirror']['directions'] = {'IN': '101'}
|
||||
|
||||
|
||||
class TaasTestCase(base.BaseTestCase):
|
||||
"""Test case base class for all unit tests."""
|
||||
|
|
|
@ -0,0 +1,381 @@
|
|||
# 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.
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from neutron_lib.plugins.ml2 import ovs_constants as n_ovs_consts
|
||||
|
||||
import neutron_taas.services.taas.drivers.linux.ovs_constants \
|
||||
as taas_ovs_consts
|
||||
from neutron_taas.services.taas.drivers.linux import ovs_taas
|
||||
from neutron_taas.tests import base
|
||||
|
||||
|
||||
class FakeVifPort(object):
|
||||
def __init__(self, port_name, ofport, vif_id, vif_mac, switch):
|
||||
self.port_name = port_name
|
||||
self.ofport = ofport
|
||||
self.vif_id = vif_id
|
||||
self.vif_mac = vif_mac
|
||||
self.switch = switch
|
||||
|
||||
|
||||
class FakeBridge(object):
|
||||
|
||||
def __init__(self, br_name):
|
||||
self.br_name = br_name
|
||||
|
||||
def add_patch_port(self, local_name, remote_name):
|
||||
pass
|
||||
|
||||
def get_port_ofport(self, port_name):
|
||||
return base.FAKE_OF_PORT
|
||||
|
||||
def add_flow(self, **kwargs):
|
||||
pass
|
||||
|
||||
def delete_flows(self, **kwargs):
|
||||
pass
|
||||
|
||||
def get_vif_port_by_id(self, port_id):
|
||||
port = base.FAKE_TAP_SERVICE_OVS['port']
|
||||
return FakeVifPort(
|
||||
port_name=base.FAKE_OF_PORT['port_name'],
|
||||
ofport=base.FAKE_OF_PORT['ofport'],
|
||||
vif_id=port_id,
|
||||
vif_mac=port['mac_address'],
|
||||
switch=port['binding:vif_details']['bridge_name']
|
||||
)
|
||||
|
||||
def get_port_tag_dict(self):
|
||||
return base.FAKE_PORT_DICT
|
||||
|
||||
|
||||
class TestOvsDriverTaas(base.TaasTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOvsDriverTaas, self).setUp()
|
||||
|
||||
def _create_tun_flood_flow(self):
|
||||
return ''
|
||||
|
||||
def _init_taas_driver(self, mock_ovs_ext_api, mock_tap_ext):
|
||||
obj = ovs_taas.OvsTaasDriver()
|
||||
obj.agent_api = mock_ovs_ext_api
|
||||
obj.tunnel_types = 'vxlan'
|
||||
|
||||
obj._create_tunnel_flood_flow_action = self._create_tun_flood_flow
|
||||
|
||||
mock_br_int = mock_ovs_ext_api.request_int_br.return_value
|
||||
mock_br_int.add_flow = mock.Mock()
|
||||
mock_br_int.delete_flows = mock.Mock()
|
||||
mock_br_int.add_patch_port = mock.Mock()
|
||||
|
||||
mock_br_tun = mock_ovs_ext_api.request_tun_br.return_value
|
||||
mock_br_tun.add_flow = mock.Mock()
|
||||
mock_br_tun.delete_flows = mock.Mock()
|
||||
mock_br_tun.add_patch_port = mock.Mock()
|
||||
|
||||
mock_tap_bridge = mock_tap_ext.return_value
|
||||
mock_tap_bridge.create.return_value = None
|
||||
mock_tap_bridge.add_flow = mock.Mock()
|
||||
mock_tap_bridge.delete_flows = mock.Mock()
|
||||
|
||||
obj.initialize()
|
||||
|
||||
return obj, mock_tap_bridge, mock_br_int, mock_br_tun
|
||||
|
||||
def _vlidate_bridge_initialization(self, mock_ovs_ext_api,
|
||||
mock_tap_bridge, mock_br_int,
|
||||
mock_br_tun):
|
||||
mock_ovs_ext_api.request_int_br.assert_called_once()
|
||||
mock_ovs_ext_api.request_tun_br.assert_called_once()
|
||||
|
||||
mock_tap_bridge.create.assert_called_once()
|
||||
|
||||
mock_br_int.add_patch_port.assert_called_once()
|
||||
mock_br_tun.add_patch_port.assert_called_once()
|
||||
mock_tap_bridge.add_patch_port.assert_has_calls([
|
||||
mock.call('patch-tap-int', 'patch-int-tap'),
|
||||
mock.call('patch-tap-tun', 'patch-tun-tap')
|
||||
])
|
||||
|
||||
mock_tap_bridge.add_flow.assert_has_calls([
|
||||
mock.call(table=0, priority=1, in_port=mock.ANY,
|
||||
actions='resubmit(,1)'),
|
||||
mock.call(table=0, priority=1, in_port=mock.ANY,
|
||||
actions='resubmit(,2)'),
|
||||
mock.call(table=0, priority=0, actions='drop'),
|
||||
mock.call(table=1, priority=0, actions=mock.ANY),
|
||||
mock.call(table=2, priority=0, actions='drop'),
|
||||
])
|
||||
|
||||
mock_br_tun.add_flow.assert_has_calls([
|
||||
mock.call(table=0, priority=1, in_port=mock.ANY,
|
||||
actions='resubmit(,30)'),
|
||||
mock.call(table=30, priority=0, actions='resubmit(,31)'),
|
||||
mock.call(table=35, priority=2, reg0=0, actions='resubmit(,36)'),
|
||||
mock.call(table=35, priority=1, reg0=1, actions='resubmit(,36)'),
|
||||
mock.call(table=35, priority=1, reg0=2, actions='resubmit(,37)'),
|
||||
mock.call(table=36, priority=0, actions='drop'),
|
||||
mock.call(table=37, priority=0, actions='drop'),
|
||||
mock.call(table=38, priority=2, reg0=0, actions=mock.ANY),
|
||||
mock.call(table=38, priority=1, reg0=1, actions=mock.ANY),
|
||||
mock.call(table=39, priority=1, actions=mock.ANY)
|
||||
])
|
||||
|
||||
@mock.patch('neutron.plugins.ml2.drivers.openvswitch.agent.'
|
||||
'ovs_agent_extension_api.OVSAgentExtensionAPI')
|
||||
@mock.patch('neutron_taas.services.taas.drivers.linux.ovs_taas.'
|
||||
'OVSBridge_tap_extension')
|
||||
def test_create_tap_service(self, mock_tap_ext, mock_api):
|
||||
tap_service = base.FAKE_TAP_SERVICE_OVS
|
||||
|
||||
mock_ovs_ext_api = mock_api.return_value
|
||||
mock_ovs_ext_api.request_int_br.return_value = FakeBridge('br_int')
|
||||
mock_ovs_ext_api.request_tun_br.return_value = FakeBridge('br_tun')
|
||||
|
||||
obj, mock_tap_bridge, mock_br_int, mock_br_tun = \
|
||||
self._init_taas_driver(mock_ovs_ext_api, mock_tap_ext)
|
||||
self._vlidate_bridge_initialization(mock_ovs_ext_api, mock_tap_bridge,
|
||||
mock_br_int, mock_br_tun)
|
||||
|
||||
mock_tap_bridge.reset_mock()
|
||||
mock_br_int.add_flow.reset_mock()
|
||||
mock_br_tun.add_flow.reset_mock()
|
||||
with mock.patch('neutron.agent.linux.utils.execute'):
|
||||
obj.create_tap_service(tap_service)
|
||||
|
||||
mock_tap_bridge.add_flow.assert_has_calls([
|
||||
mock.call(table=1, priority=1, dl_vlan=mock.ANY,
|
||||
actions='output:in_port'),
|
||||
mock.call(table=2, priority=1, dl_vlan=mock.ANY, actions=mock.ANY)
|
||||
])
|
||||
mock_br_int.add_flow.assert_called_once_with(
|
||||
table=0, priority=25, in_port=mock.ANY, dl_vlan=mock.ANY,
|
||||
actions=mock.ANY
|
||||
)
|
||||
mock_br_tun.add_flow.assert_has_calls([
|
||||
mock.call(table=n_ovs_consts.GRE_TUN_TO_LV, priority=1,
|
||||
tun_id=mock.ANY, actions=mock.ANY),
|
||||
mock.call(table=n_ovs_consts.VXLAN_TUN_TO_LV, priority=1,
|
||||
tun_id=mock.ANY, actions=mock.ANY),
|
||||
mock.call(table=n_ovs_consts.GENEVE_TUN_TO_LV, priority=1,
|
||||
tun_id=mock.ANY, actions=mock.ANY),
|
||||
mock.call(table=taas_ovs_consts.TAAS_DST_CHECK, priority=1,
|
||||
tun_id=mock.ANY, actions='resubmit(,38)')
|
||||
])
|
||||
|
||||
@mock.patch('neutron.plugins.ml2.drivers.openvswitch.agent.'
|
||||
'ovs_agent_extension_api.OVSAgentExtensionAPI')
|
||||
@mock.patch('neutron_taas.services.taas.drivers.linux.ovs_taas.'
|
||||
'OVSBridge_tap_extension')
|
||||
def test_delete_tap_service(self, mock_tap_ext, mock_api):
|
||||
tap_service = base.FAKE_TAP_SERVICE_OVS
|
||||
|
||||
mock_ovs_ext_api = mock_api.return_value
|
||||
mock_ovs_ext_api.request_int_br.return_value = FakeBridge('br_int')
|
||||
mock_ovs_ext_api.request_tun_br.return_value = FakeBridge('br_tun')
|
||||
|
||||
obj, mock_tap_bridge, mock_br_int, mock_br_tun = \
|
||||
self._init_taas_driver(mock_ovs_ext_api, mock_tap_ext)
|
||||
self._vlidate_bridge_initialization(mock_ovs_ext_api, mock_tap_bridge,
|
||||
mock_br_int, mock_br_tun)
|
||||
|
||||
mock_tap_bridge.delete_flows.reset_mock()
|
||||
mock_br_int.delete_flows.reset_mock()
|
||||
mock_br_tun.delete_flows.reset_mock()
|
||||
|
||||
obj.delete_tap_service(tap_service)
|
||||
|
||||
mock_tap_bridge.delete_flows.assert_has_calls([
|
||||
mock.call(table=1, dl_vlan=mock.ANY),
|
||||
mock.call(table=2, dl_vlan=mock.ANY),
|
||||
])
|
||||
mock_br_int.delete_flows.assert_called_once_with(
|
||||
table=0, in_port=mock.ANY, dl_vlan=mock.ANY,
|
||||
)
|
||||
mock_br_tun.delete_flows.assert_has_calls([
|
||||
mock.call(table=n_ovs_consts.GRE_TUN_TO_LV, tun_id=mock.ANY),
|
||||
mock.call(table=n_ovs_consts.VXLAN_TUN_TO_LV, tun_id=mock.ANY),
|
||||
mock.call(table=n_ovs_consts.GENEVE_TUN_TO_LV, tun_id=mock.ANY),
|
||||
mock.call(table=taas_ovs_consts.TAAS_DST_CHECK, tun_id=mock.ANY),
|
||||
mock.call(table=taas_ovs_consts.TAAS_SRC_CHECK, tun_id=mock.ANY)
|
||||
])
|
||||
|
||||
@mock.patch('neutron.plugins.ml2.drivers.openvswitch.agent.'
|
||||
'ovs_agent_extension_api.OVSAgentExtensionAPI')
|
||||
@mock.patch('neutron_taas.services.taas.drivers.linux.ovs_taas.'
|
||||
'OVSBridge_tap_extension')
|
||||
def test_create_tap_flow(self, mock_tap_ext, mock_api):
|
||||
tap_flow = base.FAKE_TAP_FLOW
|
||||
|
||||
mock_ovs_ext_api = mock_api.return_value
|
||||
mock_ovs_ext_api.request_int_br.return_value = FakeBridge('br_int')
|
||||
mock_ovs_ext_api.request_tun_br.return_value = FakeBridge('br_tun')
|
||||
|
||||
obj, mock_tap_bridge, mock_br_int, mock_br_tun = \
|
||||
self._init_taas_driver(mock_ovs_ext_api, mock_tap_ext)
|
||||
self._vlidate_bridge_initialization(mock_ovs_ext_api, mock_tap_bridge,
|
||||
mock_br_int, mock_br_tun)
|
||||
|
||||
mock_tap_bridge.reset_mock()
|
||||
mock_br_int.add_flow.reset_mock()
|
||||
mock_br_tun.add_flow.reset_mock()
|
||||
obj.create_tap_flow(tap_flow)
|
||||
|
||||
mock_tap_bridge.add_flow.assert_not_called()
|
||||
mock_br_tun.add_flow.assert_has_calls([
|
||||
mock.call(table=n_ovs_consts.GRE_TUN_TO_LV, priority=1,
|
||||
tun_id=mock.ANY, actions=mock.ANY),
|
||||
mock.call(table=n_ovs_consts.VXLAN_TUN_TO_LV, priority=1,
|
||||
tun_id=mock.ANY, actions=mock.ANY),
|
||||
mock.call(table=n_ovs_consts.GENEVE_TUN_TO_LV, priority=1,
|
||||
tun_id=mock.ANY, actions=mock.ANY),
|
||||
mock.call(table=taas_ovs_consts.TAAS_SRC_CHECK, priority=1,
|
||||
tun_id=mock.ANY, actions=mock.ANY)
|
||||
])
|
||||
mock_br_int.add_flow.assert_called_once_with(
|
||||
table=0, priority=20, dl_dst=tap_flow['port_mac'],
|
||||
actions=mock.ANY
|
||||
)
|
||||
|
||||
@mock.patch('neutron.plugins.ml2.drivers.openvswitch.agent.'
|
||||
'ovs_agent_extension_api.OVSAgentExtensionAPI')
|
||||
@mock.patch('neutron_taas.services.taas.drivers.linux.ovs_taas.'
|
||||
'OVSBridge_tap_extension')
|
||||
def test_delete_tap_flow(self, mock_tap_ext, mock_api):
|
||||
tap_flow = base.FAKE_TAP_FLOW
|
||||
|
||||
mock_ovs_ext_api = mock_api.return_value
|
||||
mock_ovs_ext_api.request_int_br.return_value = FakeBridge('br_int')
|
||||
mock_ovs_ext_api.request_tun_br.return_value = FakeBridge('br_tun')
|
||||
|
||||
obj, mock_tap_bridge, mock_br_int, mock_br_tun = \
|
||||
self._init_taas_driver(mock_ovs_ext_api, mock_tap_ext)
|
||||
self._vlidate_bridge_initialization(mock_ovs_ext_api, mock_tap_bridge,
|
||||
mock_br_int, mock_br_tun)
|
||||
|
||||
mock_tap_bridge.reset_mock()
|
||||
mock_br_int.delete_flows.reset_mock()
|
||||
mock_br_tun.delete_flows.reset_mock()
|
||||
|
||||
obj.delete_tap_flow(tap_flow)
|
||||
|
||||
mock_tap_bridge.delete_flows.assert_not_called()
|
||||
mock_br_tun.delete_flows.assert_not_called()
|
||||
mock_br_int.delete_flows.assert_called_once_with(
|
||||
table=0, dl_dst=tap_flow['port_mac']
|
||||
)
|
||||
|
||||
@mock.patch('neutron.plugins.ml2.drivers.openvswitch.agent.'
|
||||
'ovs_agent_extension_api.OVSAgentExtensionAPI')
|
||||
@mock.patch('neutron_taas.services.taas.drivers.linux.ovs_taas.'
|
||||
'OVSBridge_tap_extension')
|
||||
def test_create_tap_mirror_out_direction(self, mock_tap_ext, mock_api):
|
||||
tap_mirror = base.FAKE_TAP_MIRROR_OUT
|
||||
|
||||
mock_ovs_ext_api = mock_api.return_value
|
||||
mock_ovs_ext_api.request_int_br.return_value = FakeBridge('br_int')
|
||||
mock_ovs_ext_api.request_tun_br.return_value = FakeBridge('br_tun')
|
||||
|
||||
obj, mock_tap_bridge, mock_br_int, mock_br_tun = \
|
||||
self._init_taas_driver(mock_ovs_ext_api, mock_tap_ext)
|
||||
self._vlidate_bridge_initialization(mock_ovs_ext_api, mock_tap_bridge,
|
||||
mock_br_int, mock_br_tun)
|
||||
|
||||
mock_tap_bridge.reset_mock()
|
||||
mock_br_int.add_flow.reset_mock()
|
||||
obj.create_tap_mirror(tap_mirror)
|
||||
|
||||
mock_tap_bridge.add_flow.assert_has_calls([
|
||||
mock.call(table=taas_ovs_consts.TAAS_RECV_LOC, priority=20,
|
||||
dl_src=tap_mirror['port']['mac_address'],
|
||||
actions=mock.ANY),
|
||||
mock.call(table=taas_ovs_consts.TAAS_RECV_LOC, priority=1,
|
||||
dl_dst=tap_mirror['port']['mac_address'],
|
||||
actions=mock.ANY),
|
||||
mock.call(table=taas_ovs_consts.TAAS_RECV_REM, priority=1,
|
||||
dl_dst=tap_mirror['port']['mac_address'],
|
||||
actions=mock.ANY),
|
||||
])
|
||||
mock_br_int.add_flow.assert_called_once_with(
|
||||
table=0, priority=20, in_port=mock.ANY, actions=mock.ANY
|
||||
)
|
||||
|
||||
@mock.patch('neutron.plugins.ml2.drivers.openvswitch.agent.'
|
||||
'ovs_agent_extension_api.OVSAgentExtensionAPI')
|
||||
@mock.patch('neutron_taas.services.taas.drivers.linux.ovs_taas.'
|
||||
'OVSBridge_tap_extension')
|
||||
def test_create_tap_mirror_in_direction(self, mock_tap_ext, mock_api):
|
||||
tap_mirror = base.FAKE_TAP_MIRROR_IN
|
||||
|
||||
mock_ovs_ext_api = mock_api.return_value
|
||||
mock_ovs_ext_api.request_int_br.return_value = FakeBridge('br_int')
|
||||
mock_ovs_ext_api.request_tun_br.return_value = FakeBridge('br_tun')
|
||||
|
||||
obj, mock_tap_bridge, mock_br_int, mock_br_tun = \
|
||||
self._init_taas_driver(mock_ovs_ext_api, mock_tap_ext)
|
||||
self._vlidate_bridge_initialization(mock_ovs_ext_api, mock_tap_bridge,
|
||||
mock_br_int, mock_br_tun)
|
||||
|
||||
mock_tap_bridge.reset_mock()
|
||||
mock_br_int.add_flow.reset_mock()
|
||||
obj.create_tap_mirror(tap_mirror)
|
||||
|
||||
mock_tap_bridge.add_flow.assert_has_calls([
|
||||
mock.call(table=taas_ovs_consts.TAAS_RECV_LOC, priority=20,
|
||||
dl_dst=tap_mirror['port']['mac_address'],
|
||||
actions=mock.ANY),
|
||||
mock.call(table=taas_ovs_consts.TAAS_RECV_LOC, priority=1,
|
||||
dl_dst=tap_mirror['port']['mac_address'],
|
||||
actions=mock.ANY),
|
||||
mock.call(table=taas_ovs_consts.TAAS_RECV_REM, priority=1,
|
||||
dl_dst=tap_mirror['port']['mac_address'],
|
||||
actions=mock.ANY),
|
||||
])
|
||||
mock_br_int.add_flow.assert_called_once_with(
|
||||
table=0, priority=20,
|
||||
dl_dst=base.FAKE_TAP_MIRROR_IN['port']['mac_address'],
|
||||
actions=mock.ANY
|
||||
)
|
||||
|
||||
@mock.patch('neutron.plugins.ml2.drivers.openvswitch.agent.'
|
||||
'ovs_agent_extension_api.OVSAgentExtensionAPI')
|
||||
@mock.patch('neutron_taas.services.taas.drivers.linux.ovs_taas.'
|
||||
'OVSBridge_tap_extension')
|
||||
def test_delete_tap_mirror(self, mock_tap_ext, mock_api):
|
||||
tap_mirror = base.FAKE_TAP_MIRROR_OUT
|
||||
|
||||
mock_ovs_ext_api = mock_api.return_value
|
||||
mock_ovs_ext_api.request_int_br.return_value = FakeBridge('br_int')
|
||||
mock_ovs_ext_api.request_tun_br.return_value = FakeBridge('br_tun')
|
||||
|
||||
obj, mock_tap_bridge, mock_br_int, mock_br_tun = \
|
||||
self._init_taas_driver(mock_ovs_ext_api, mock_tap_ext)
|
||||
self._vlidate_bridge_initialization(mock_ovs_ext_api, mock_tap_bridge,
|
||||
mock_br_int, mock_br_tun)
|
||||
|
||||
mock_tap_bridge.reset_mock()
|
||||
mock_br_int.delete_flows.reset_mock()
|
||||
|
||||
obj.delete_tap_mirror(tap_mirror)
|
||||
|
||||
mock_tap_bridge.delete_flows.assert_has_calls([
|
||||
mock.call(table=taas_ovs_consts.TAAS_RECV_REM,
|
||||
dl_dst=tap_mirror['port']['mac_address']),
|
||||
mock.call(table=taas_ovs_consts.TAAS_RECV_LOC,
|
||||
dl_dst=tap_mirror['port']['mac_address']),
|
||||
mock.call(table=taas_ovs_consts.TAAS_RECV_LOC,
|
||||
dl_src=tap_mirror['port']['mac_address']),
|
||||
])
|
||||
mock_br_int.delete_flows.assert_called_once()
|
|
@ -21,21 +21,6 @@ from neutron_taas.services.taas.drivers.linux import sriov_nic_exceptions \
|
|||
from neutron_taas.services.taas.drivers.linux import sriov_nic_taas
|
||||
from neutron_taas.tests import base
|
||||
|
||||
FAKE_PORT_PARAMS = {
|
||||
'mac': '52:54:00:12:35:02', 'pci_slot': 3, 'vf_index': '89',
|
||||
'pf_device': 'net_enp0s3_52_54_00_12_35_02', 'src_vlans': '20'}
|
||||
|
||||
FAKE_TAP_SERVICE = {'port': {
|
||||
'id': 'fake_1', 'mac_address': "52:54:00:12:35:02",
|
||||
'binding:profile': {'pci_slot': 3},
|
||||
'binding:vif_details': {'vlan': '20'}}}
|
||||
|
||||
FAKE_TAP_FLOW = {'port': FAKE_TAP_SERVICE['port'],
|
||||
'ts_port': FAKE_TAP_SERVICE['port'],
|
||||
'source_vlans_list': ['4-6', '8-10', '15-18,20'],
|
||||
'vlan_filter_list': '1-5,9,18,20,27-30,4000-4095',
|
||||
'tap_flow': {'direction': 'IN', 'vlan_filter': '20'}}
|
||||
|
||||
|
||||
class TestSriovNicTaas(base.TaasTestCase):
|
||||
def setUp(self):
|
||||
|
@ -43,9 +28,9 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
|
||||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_create_tap_service(self, mock_sriov_utils):
|
||||
tap_service = FAKE_TAP_SERVICE
|
||||
tap_service = base.FAKE_TAP_SERVICE
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
return_value = FAKE_PORT_PARAMS
|
||||
return_value = base.FAKE_PORT_PARAMS
|
||||
obj = sriov_nic_taas.SriovNicTaasDriver()
|
||||
obj.initialize()
|
||||
obj.create_tap_service(tap_service)
|
||||
|
@ -55,12 +40,12 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_create_tap_service_no_pf_device_and_vf_index(
|
||||
self, mock_sriov_utils):
|
||||
tap_service = FAKE_TAP_SERVICE
|
||||
temp_fake_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
tap_service = base.FAKE_TAP_SERVICE
|
||||
temp_fake_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
temp_fake_port_params['pf_device'] = None
|
||||
temp_fake_port_params['vf_index'] = None
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
return_value = FAKE_PORT_PARAMS
|
||||
return_value = base.FAKE_PORT_PARAMS
|
||||
obj = sriov_nic_taas.SriovNicTaasDriver()
|
||||
obj.initialize()
|
||||
self.assertIsNone(obj.create_tap_service(tap_service))
|
||||
|
@ -69,9 +54,9 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
|
||||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_delete_tap_service(self, mock_sriov_utils):
|
||||
tap_service = FAKE_TAP_SERVICE
|
||||
tap_service = base.FAKE_TAP_SERVICE
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
return_value = FAKE_PORT_PARAMS
|
||||
return_value = base.FAKE_PORT_PARAMS
|
||||
obj = sriov_nic_taas.SriovNicTaasDriver()
|
||||
obj.initialize()
|
||||
obj.create_tap_service(tap_service)
|
||||
|
@ -81,12 +66,12 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_delete_tap_service_no_pf_device_and_vf_index(
|
||||
self, mock_sriov_utils):
|
||||
tap_service = FAKE_TAP_SERVICE
|
||||
temp_fake_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
tap_service = base.FAKE_TAP_SERVICE
|
||||
temp_fake_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
temp_fake_port_params['pf_device'] = None
|
||||
temp_fake_port_params['vf_index'] = None
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
return_value = FAKE_PORT_PARAMS
|
||||
return_value = base.FAKE_PORT_PARAMS
|
||||
obj = sriov_nic_taas.SriovNicTaasDriver()
|
||||
obj.initialize()
|
||||
self.assertIsNone(obj.create_tap_service(tap_service))
|
||||
|
@ -95,11 +80,11 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
|
||||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_create_tap_flow(self, mock_sriov_utils):
|
||||
tap_flow = {'port': FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': FAKE_TAP_SERVICE['port'],
|
||||
tap_flow = {'port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': base.FAKE_TAP_SERVICE['port'],
|
||||
'vlan_filter_list': '1-5,9,18,20,27-30,4000-4095',
|
||||
'tap_flow': {'direction': 'IN', 'vlan_filter': '20'}}
|
||||
src_port_params = ts_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
src_port_params = ts_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
side_effect = [src_port_params, ts_port_params]
|
||||
obj = sriov_nic_taas.SriovNicTaasDriver()
|
||||
|
@ -112,10 +97,10 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_create_tap_flow_no_vlan_filter_on_source_and_probe(
|
||||
self, mock_sriov_utils):
|
||||
tap_flow = {'port': FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': FAKE_TAP_SERVICE['port'],
|
||||
tap_flow = {'port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_flow': {'direction': 'IN', 'vlan_filter': '20'}}
|
||||
src_port_params = ts_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
src_port_params = ts_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
ts_port_params['vlan_filter'] = None
|
||||
src_port_params['src_vlans'] = None
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
|
@ -130,10 +115,10 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_create_tap_flow_no_source_pci_slot(
|
||||
self, mock_sriov_utils):
|
||||
tap_flow = {'port': FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': FAKE_TAP_SERVICE['port'],
|
||||
tap_flow = {'port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_flow': {'direction': 'IN', 'vlan_filter': 20}}
|
||||
src_port_params = ts_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
src_port_params = ts_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
src_port_params['pci_slot'] = None
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
side_effect = [src_port_params, ts_port_params]
|
||||
|
@ -145,11 +130,11 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_create_tap_flow_no_ts_pci_slot(
|
||||
self, mock_sriov_utils):
|
||||
tap_flow = {'port': FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': FAKE_TAP_SERVICE['port'],
|
||||
tap_flow = {'port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_flow': {'direction': 'IN', 'vlan_filter': 20}}
|
||||
src_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
ts_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
src_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
ts_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
ts_port_params['pci_slot'] = None
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
side_effect = [src_port_params, ts_port_params]
|
||||
|
@ -161,11 +146,11 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_create_tap_flow_different_pf_devices(
|
||||
self, mock_sriov_utils):
|
||||
tap_flow = {'port': FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': FAKE_TAP_SERVICE['port'],
|
||||
tap_flow = {'port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_flow': {'direction': 'IN', 'vlan_filter': 20}}
|
||||
src_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
ts_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
src_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
ts_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
ts_port_params['pf_device'] = 'net_enp0s3_52_54_00_12_35_02'
|
||||
src_port_params['pf_device'] = 'net_enp0s8_52_54_00_12_35_01'
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
|
@ -176,12 +161,12 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
|
||||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_delete_tap_flow(self, mock_sriov_utils):
|
||||
tap_flow = {'port': FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': FAKE_TAP_SERVICE['port'],
|
||||
tap_flow = {'port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': base.FAKE_TAP_SERVICE['port'],
|
||||
'source_vlans_list': ['4-6', '8-10', '15-18,20'],
|
||||
'vlan_filter_list': ['1-5,9,18,20,27-30,4000-4095'],
|
||||
'tap_flow': {'direction': 'IN', 'vlan_filter': '20'}}
|
||||
src_port_params = ts_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
src_port_params = ts_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
side_effect = [src_port_params, ts_port_params]
|
||||
obj = sriov_nic_taas.SriovNicTaasDriver()
|
||||
|
@ -193,12 +178,12 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_delete_tap_flow_no_source_pci_slot(
|
||||
self, mock_sriov_utils):
|
||||
tap_flow = {'port': FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': FAKE_TAP_SERVICE['port'],
|
||||
tap_flow = {'port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': base.FAKE_TAP_SERVICE['port'],
|
||||
'source_vlans_list': [4, 5, 9],
|
||||
'tap_flow': {'direction': 'IN', 'vlan_filter': 20}}
|
||||
src_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
ts_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
src_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
ts_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
src_port_params['pci_slot'] = None
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
side_effect = [src_port_params, ts_port_params]
|
||||
|
@ -210,11 +195,11 @@ class TestSriovNicTaas(base.TaasTestCase):
|
|||
@mock.patch.object(sriov_nic_taas, 'sriov_utils')
|
||||
def test_delete_tap_flow_no_ts_pci_slot(
|
||||
self, mock_sriov_utils):
|
||||
tap_flow = {'port': FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': FAKE_TAP_SERVICE['port'],
|
||||
tap_flow = {'port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_service_port': base.FAKE_TAP_SERVICE['port'],
|
||||
'tap_flow': {'direction': 'IN', 'vlan_filter': 20}}
|
||||
src_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
ts_port_params = copy.deepcopy(FAKE_PORT_PARAMS)
|
||||
src_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
ts_port_params = copy.deepcopy(base.FAKE_PORT_PARAMS)
|
||||
ts_port_params['pci_slot'] = None
|
||||
mock_sriov_utils.SriovNicUtils().get_sriov_port_params.\
|
||||
side_effect = [src_port_params, ts_port_params]
|
||||
|
|
|
@ -53,7 +53,7 @@ class TestTapMirrorPlugin(testlib_api.SqlTestCase):
|
|||
}
|
||||
self._tap_mirror = {
|
||||
'project_id': self._project_id,
|
||||
',tenant_id': self._tenant_id,
|
||||
'tenant_id': self._tenant_id,
|
||||
'name': 'MyMirror',
|
||||
'description': 'This is my Tap Mirror',
|
||||
'port_id': self._port_id,
|
||||
|
@ -63,7 +63,8 @@ class TestTapMirrorPlugin(testlib_api.SqlTestCase):
|
|||
}
|
||||
|
||||
@contextlib.contextmanager
|
||||
def tap_mirror(self):
|
||||
def tap_mirror(self, **kwargs):
|
||||
self._tap_mirror.update(kwargs)
|
||||
req = {
|
||||
'tap_mirror': self._tap_mirror,
|
||||
}
|
||||
|
@ -72,8 +73,18 @@ class TestTapMirrorPlugin(testlib_api.SqlTestCase):
|
|||
mirror = self._plugin.create_tap_mirror(self._context, req)
|
||||
self._tap_mirror['id'] = mock.ANY
|
||||
|
||||
# TODO(lajoskatona): Add more checks for the pre/post phases
|
||||
# (check the next patches)
|
||||
self.driver.assert_has_calls([
|
||||
mock.call.create_tap_mirror_precommit(mock.ANY),
|
||||
mock.call.create_tap_mirror_postcommit(mock.ANY),
|
||||
])
|
||||
pre_call_args = self.driver.create_tap_mirror_precommit.call_args[0][0]
|
||||
self.assertEqual(self._context, pre_call_args._plugin_context)
|
||||
self.assertEqual(self._tap_mirror, pre_call_args.tap_mirror)
|
||||
|
||||
post_call_args = self.driver.create_tap_mirror_postcommit.call_args
|
||||
post_call_args = post_call_args[0][0]
|
||||
self.assertEqual(self._context, post_call_args._plugin_context)
|
||||
self.assertEqual(self._tap_mirror, post_call_args.tap_mirror)
|
||||
|
||||
yield self._plugin.get_tap_mirror(self._context,
|
||||
mirror['id'])
|
||||
|
@ -90,6 +101,43 @@ class TestTapMirrorPlugin(testlib_api.SqlTestCase):
|
|||
pass
|
||||
self.assertEqual([], self.driver.mock_calls)
|
||||
|
||||
def test_create_duplicate_tunnel_id(self):
|
||||
with self.tap_mirror() as tm1:
|
||||
# TODO(lajoskatona): change this to an import to neutron-lib when
|
||||
# https://review.opendev.org/c/openstack/neutron-lib/+/895603 is
|
||||
# released.
|
||||
with mock.patch.object(self._plugin, 'get_tap_mirrors',
|
||||
return_value=[tm1]):
|
||||
with testtools.ExpectedException(
|
||||
tm_db.TapMirrorTunnelConflict), \
|
||||
self.tap_mirror(directions={"IN": 101}):
|
||||
pass
|
||||
|
||||
def test_create_different_tunnel_id(self):
|
||||
with self.tap_mirror() as tm1:
|
||||
with mock.patch.object(self._plugin, 'get_tap_mirrors',
|
||||
return_value=[tm1]):
|
||||
with self.tap_mirror(directions={"IN": 102}):
|
||||
pass
|
||||
|
||||
def test_same_tunnel_id_different_direction(self):
|
||||
with self.tap_mirror() as tm1:
|
||||
with mock.patch.object(self._plugin, 'get_tap_mirrors',
|
||||
return_value=[tm1]):
|
||||
with testtools.ExpectedException(
|
||||
tm_db.TapMirrorTunnelConflict), \
|
||||
self.tap_mirror(directions={"OUT": 101}):
|
||||
pass
|
||||
|
||||
def test_two_direction_tunnel_id(self):
|
||||
with self.tap_mirror(directions={'IN': 101, 'OUT': 102}) as tm1:
|
||||
with mock.patch.object(self._plugin, 'get_tap_mirrors',
|
||||
return_value=[tm1]):
|
||||
with testtools.ExpectedException(
|
||||
tm_db.TapMirrorTunnelConflict), \
|
||||
self.tap_mirror(directions={"OUT": 101}):
|
||||
pass
|
||||
|
||||
def test_delete_tap_mrror(self):
|
||||
with self.tap_mirror() as tm:
|
||||
self._plugin.delete_tap_mirror(self._context, tm['id'])
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Add possibility to create (CRUD) ``tap_mirrors`` with ``OVS`` backend.
|
Loading…
Reference in New Issue