Move port validation support into the driver
Each firewall driver have specific checks to do on port validation (like checks if the VIF port type corresponds to a type supported by the driver (aka the SDN controller)). This patch adds two methods to the driver interface to validate if the VM or the router port is supported (just have to return a boolean). Change-Id: I8fdf0956ac5428558aae413e610d13c4a4a56273 Closes-Bug: #1803723
This commit is contained in:
@@ -20,5 +20,5 @@ from neutron_fwaas._i18n import _
|
|||||||
|
|
||||||
# TODO(annp): migrate to neutron-lib after Queen release
|
# TODO(annp): migrate to neutron-lib after Queen release
|
||||||
class FirewallGroupPortNotSupported(n_exc.Conflict):
|
class FirewallGroupPortNotSupported(n_exc.Conflict):
|
||||||
message = _("Port %(port_id)s is not supported by firewall L2 driver. "
|
message = _("Port %(port_id)s is not supported by firewall driver "
|
||||||
"This may happen due to incompatible driver combination.")
|
"'%(driver_name)s'.")
|
||||||
|
@@ -66,6 +66,7 @@ class FirewallPluginV2(Firewallv2PluginBase):
|
|||||||
"although running multiple drivers in parallel is "
|
"although running multiple drivers in parallel is "
|
||||||
"not yet supported")
|
"not yet supported")
|
||||||
|
|
||||||
|
self.driver_name = default_provider
|
||||||
self.driver = drivers[default_provider]
|
self.driver = drivers[default_provider]
|
||||||
|
|
||||||
# start rpc listener if driver required
|
# start rpc listener if driver required
|
||||||
@@ -151,7 +152,8 @@ class FirewallPluginV2(Firewallv2PluginBase):
|
|||||||
"""Validate firewall group associated ports
|
"""Validate firewall group associated ports
|
||||||
|
|
||||||
Check if the firewall group associated ports have the same project
|
Check if the firewall group associated ports have the same project
|
||||||
owner and is router interface type or a compute layer 2.
|
owner and is router interface type or a compute layer 2 and supported
|
||||||
|
by the firewall driver
|
||||||
:param context: neutron context
|
:param context: neutron context
|
||||||
:param tenant_id: firewall group project ID
|
:param tenant_id: firewall group project ID
|
||||||
:param fwg_ports: firewall group associated ports
|
:param fwg_ports: firewall group associated ports
|
||||||
@@ -164,19 +166,20 @@ class FirewallPluginV2(Firewallv2PluginBase):
|
|||||||
raise f_exc.FirewallGroupPortInvalidProject(
|
raise f_exc.FirewallGroupPortInvalidProject(
|
||||||
port_id=port_id, project_id=port['tenant_id'])
|
port_id=port_id, project_id=port['tenant_id'])
|
||||||
device_owner = port.get('device_owner', '')
|
device_owner = port.get('device_owner', '')
|
||||||
if (device_owner not in nl_constants.ROUTER_INTERFACE_OWNERS and
|
if device_owner in nl_constants.ROUTER_INTERFACE_OWNERS:
|
||||||
not device_owner.startswith(
|
if not self.driver.is_supported_l3_port(port):
|
||||||
nl_constants.DEVICE_OWNER_COMPUTE_PREFIX)):
|
raise exceptions.FirewallGroupPortNotSupported(
|
||||||
|
driver_name=self.driver_name, port_id=port_id)
|
||||||
|
elif device_owner.startswith(
|
||||||
|
nl_constants.DEVICE_OWNER_COMPUTE_PREFIX):
|
||||||
|
if not self._is_supported_l2_port(context, port_id):
|
||||||
|
raise exceptions.FirewallGroupPortNotSupported(
|
||||||
|
driver_name=self.driver_name, port_id=port_id)
|
||||||
|
else:
|
||||||
raise f_exc.FirewallGroupPortInvalid(port_id=port_id)
|
raise f_exc.FirewallGroupPortInvalid(port_id=port_id)
|
||||||
if (device_owner.startswith(
|
|
||||||
nl_constants.DEVICE_OWNER_COMPUTE_PREFIX) and not
|
|
||||||
self._is_supported_by_fw_l2_driver(context, port_id)):
|
|
||||||
raise exceptions.FirewallGroupPortNotSupported(port_id=port_id)
|
|
||||||
|
|
||||||
# TODO(ethuleau): move that check in the driver. Each driver can have
|
def _is_supported_l2_port(self, context, port_id):
|
||||||
# different support
|
"""Whether this l2 port is supported"""
|
||||||
def _is_supported_by_fw_l2_driver(self, context, port_id):
|
|
||||||
"""Whether this port is supported by firewall l2 driver"""
|
|
||||||
|
|
||||||
# Re-fetch to get up-to-date data from db
|
# Re-fetch to get up-to-date data from db
|
||||||
port = self._core_plugin.get_port(context, id=port_id)
|
port = self._core_plugin.get_port(context, id=port_id)
|
||||||
@@ -186,18 +189,7 @@ class FirewallPluginV2(Firewallv2PluginBase):
|
|||||||
pb_def.VIF_TYPE_BINDING_FAILED]:
|
pb_def.VIF_TYPE_BINDING_FAILED]:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not port['port_security_enabled']:
|
return self.driver.is_supported_l2_port(port)
|
||||||
return True
|
|
||||||
|
|
||||||
if port[pb_def.VIF_TYPE] == pb_def.VIF_TYPE_OVS:
|
|
||||||
# TODO(annp): remove these lines after we fully support for hybrid
|
|
||||||
# port
|
|
||||||
if not port[pb_def.VIF_DETAILS][pb_def.OVS_HYBRID_PLUG]:
|
|
||||||
return True
|
|
||||||
LOG.warning("Doesn't support hybrid port at the moment")
|
|
||||||
else:
|
|
||||||
LOG.warning("Doesn't support vif type %s", port[pb_def.VIF_TYPE])
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _validate_if_firewall_group_on_ports(self, context, firewall_group,
|
def _validate_if_firewall_group_on_ports(self, context, firewall_group,
|
||||||
id=None):
|
id=None):
|
||||||
@@ -288,8 +280,8 @@ class FirewallPluginV2(Firewallv2PluginBase):
|
|||||||
|
|
||||||
context = kwargs['context']
|
context = kwargs['context']
|
||||||
port_id = updated_port['id']
|
port_id = updated_port['id']
|
||||||
# Check port is supported by firewall l2 driver or not
|
# Check port is supported by firewall driver
|
||||||
if not self._is_supported_by_fw_l2_driver(context, port_id):
|
if not self._is_supported_l2_port(context, port_id):
|
||||||
return
|
return
|
||||||
|
|
||||||
project_id = updated_port['project_id']
|
project_id = updated_port['project_id']
|
||||||
|
@@ -166,6 +166,23 @@ class FirewallAgentDriver(driver_api.FirewallDriverDB,
|
|||||||
super(FirewallAgentDriver, self).__init__(service_plugin)
|
super(FirewallAgentDriver, self).__init__(service_plugin)
|
||||||
self.agent_rpc = FirewallAgentApi(constants.FW_AGENT, cfg.CONF.host)
|
self.agent_rpc = FirewallAgentApi(constants.FW_AGENT, cfg.CONF.host)
|
||||||
|
|
||||||
|
def is_supported_l2_port(self, port):
|
||||||
|
if port[pb_def.VIF_TYPE] == pb_def.VIF_TYPE_OVS:
|
||||||
|
if not port['port_security_enabled']:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# TODO(annp): remove these lines after we fully support for hybrid
|
||||||
|
# port
|
||||||
|
if not port[pb_def.VIF_DETAILS][pb_def.OVS_HYBRID_PLUG]:
|
||||||
|
return True
|
||||||
|
LOG.warning("Doesn't support hybrid port at the moment")
|
||||||
|
else:
|
||||||
|
LOG.warning("Doesn't support vif type %s", port[pb_def.VIF_TYPE])
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_supported_l3_port(self, port):
|
||||||
|
return True
|
||||||
|
|
||||||
def start_rpc_listener(self):
|
def start_rpc_listener(self):
|
||||||
self.endpoints = [FirewallAgentCallbacks(self.firewall_db)]
|
self.endpoints = [FirewallAgentCallbacks(self.firewall_db)]
|
||||||
self.rpc_connection = n_rpc.Connection()
|
self.rpc_connection = n_rpc.Connection()
|
||||||
|
@@ -46,6 +46,12 @@ class FirewallDriver(object):
|
|||||||
def _core_plugin(self):
|
def _core_plugin(self):
|
||||||
return directory.get_plugin()
|
return directory.get_plugin()
|
||||||
|
|
||||||
|
def is_supported_l2_port(self, port):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_supported_l3_port(self, port):
|
||||||
|
return False
|
||||||
|
|
||||||
# Firewall Group
|
# Firewall Group
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def create_firewall_group(self, context, firewall_group):
|
def create_firewall_group(self, context, firewall_group):
|
||||||
|
@@ -29,9 +29,7 @@ from neutron_fwaas.tests.unit.services.firewall import test_fwaas_plugin_v2
|
|||||||
class TestFirewallDBPluginV2(test_fwaas_plugin_v2.FirewallPluginV2TestCase):
|
class TestFirewallDBPluginV2(test_fwaas_plugin_v2.FirewallPluginV2TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
provider = ('neutron_fwaas.services.firewall.service_drivers.'
|
super(TestFirewallDBPluginV2, self).setUp()
|
||||||
'driver_api.FirewallDriverDB')
|
|
||||||
super(TestFirewallDBPluginV2, self).setUp(service_provider=provider)
|
|
||||||
self.db = self.plugin.driver.firewall_db
|
self.db = self.plugin.driver.firewall_db
|
||||||
|
|
||||||
def test_get_policy_ordered_rules(self):
|
def test_get_policy_ordered_rules(self):
|
||||||
@@ -1614,7 +1612,7 @@ class TestFirewallDBPluginV2(test_fwaas_plugin_v2.FirewallPluginV2TestCase):
|
|||||||
'device_owner': 'compute:nova',
|
'device_owner': 'compute:nova',
|
||||||
'binding:vif_type': 'ovs',
|
'binding:vif_type': 'ovs',
|
||||||
}
|
}
|
||||||
self.plugin._is_supported_by_fw_l2_driver = mock.Mock(
|
self.plugin._is_supported_l2_port = mock.Mock(
|
||||||
return_value=True)
|
return_value=True)
|
||||||
with self.port(**port_args) as port1, self.port(**port_args) as port2:
|
with self.port(**port_args) as port1, self.port(**port_args) as port2:
|
||||||
port1_id = port1['port']['id']
|
port1_id = port1['port']['id']
|
||||||
|
@@ -31,6 +31,8 @@ from oslo_utils import importutils
|
|||||||
from neutron_fwaas.common import fwaas_constants
|
from neutron_fwaas.common import fwaas_constants
|
||||||
from neutron_fwaas import extensions
|
from neutron_fwaas import extensions
|
||||||
from neutron_fwaas.services.firewall import fwaas_plugin_v2
|
from neutron_fwaas.services.firewall import fwaas_plugin_v2
|
||||||
|
from neutron_fwaas.services.firewall.service_drivers.driver_api import \
|
||||||
|
FirewallDriverDB
|
||||||
from neutron_fwaas.tests import base
|
from neutron_fwaas.tests import base
|
||||||
|
|
||||||
|
|
||||||
@@ -41,6 +43,14 @@ def http_client_error(req, res):
|
|||||||
explanation=explanation)
|
explanation=explanation)
|
||||||
|
|
||||||
|
|
||||||
|
class DummyDriverDB(FirewallDriverDB):
|
||||||
|
def is_supported_l2_port(self, port):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_supported_l3_port(self, port):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class FirewallPluginV2TestCase(base.NeutronDbPluginV2TestCase):
|
class FirewallPluginV2TestCase(base.NeutronDbPluginV2TestCase):
|
||||||
DESCRIPTION = 'default description'
|
DESCRIPTION = 'default description'
|
||||||
PROTOCOL = 'tcp'
|
PROTOCOL = 'tcp'
|
||||||
@@ -64,8 +74,8 @@ class FirewallPluginV2TestCase(base.NeutronDbPluginV2TestCase):
|
|||||||
extra_service_plugins=None, extra_extension_paths=None):
|
extra_service_plugins=None, extra_extension_paths=None):
|
||||||
provider = fwaas_constants.FIREWALL_V2
|
provider = fwaas_constants.FIREWALL_V2
|
||||||
if not service_provider:
|
if not service_provider:
|
||||||
provider += (':dummy:neutron_fwaas.services.firewall.'
|
provider += (':dummy:neutron_fwaas.tests.unit.services.firewall.'
|
||||||
'service_drivers.driver_api.FirewallDriverDB:default')
|
'test_fwaas_plugin_v2.DummyDriverDB:default')
|
||||||
else:
|
else:
|
||||||
provider += ':test:' + service_provider + ':default'
|
provider += ':test:' + service_provider + ':default'
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user