NSX|V: FWaaS-V2 driver

This patch adds a driver for FWaaS V2 support in the NSX-V plugin.
It supports setting firewall rules per router interface port on the router
edge firewall.

In addition, the FWaaS TVD driver will now support NSX-V as well.

The driver code is a combination of the NSX-V3 FWaas-V2 code, and the old
NSX-V FWaaS-V1 code that is being deleted.

Change-Id: Iacc7eaff0c70b68156516008cf0277c154edd76b
This commit is contained in:
Adit Sarfaty 2018-11-26 14:55:49 +02:00
parent 85c9ae8071
commit a36a1dba74
13 changed files with 858 additions and 138 deletions

View File

@ -41,6 +41,25 @@ Optional: Update the nsx qos_peak_bw_multiplier in nsx.ini (default value is 2.0
[NSX] [NSX]
qos_peak_bw_multiplier = <i.e 10.0> qos_peak_bw_multiplier = <i.e 10.0>
FWaaS (V2) Driver
~~~~~~~~~~~~~~~~~
Add neutron-fwaas repo as an external repository and configure following flags in ``local.conf``::
[[local|localrc]]
enable_service q-fwaas-v2
Q_SERVICE_PLUGIN_CLASSES+=,firewall_v2
[[post-config|$NEUTRON_CONF]]
[fwaas]
enabled = True
driver = vmware_nsxv_edge_v2
[service_providers]
service_provider = FIREWALL_V2:fwaas_db:neutron_fwaas.services.firewall.service_drivers.agents.agents.FirewallAgentDriver:default
Note - if devstack fails due to ml2_conf.ini being missing, please copy neutron/plugins/ml2/ml2_conf.ini.sample to /etc/neutron/plugins/ml2/ml2_conf.ini and stack again.
L2GW Driver L2GW Driver
~~~~~~~~~~~ ~~~~~~~~~~~
@ -188,8 +207,8 @@ FWaaS (V2) Driver
Add neutron-fwaas repo as an external repository and configure following flags in ``local.conf``:: Add neutron-fwaas repo as an external repository and configure following flags in ``local.conf``::
[[local|localrc]] [[local|localrc]]
ENABLED_SERVICES+=,q-fwaas-v2 enable_service q-fwaas-v2
Q_SERVICE_PLUGIN_CLASSES+=,neutron_fwaas.services.firewall.fwaas_plugin_v2.FirewallPluginV2 Q_SERVICE_PLUGIN_CLASSES+=,firewall_v2
[[post-config|$NEUTRON_CONF]] [[post-config|$NEUTRON_CONF]]
[fwaas] [fwaas]
@ -199,6 +218,8 @@ Add neutron-fwaas repo as an external repository and configure following flags i
[service_providers] [service_providers]
service_provider = FIREWALL_V2:fwaas_db:neutron_fwaas.services.firewall.service_drivers.agents.agents.FirewallAgentDriver:default service_provider = FIREWALL_V2:fwaas_db:neutron_fwaas.services.firewall.service_drivers.agents.agents.FirewallAgentDriver:default
Note - if devstack fails due to ml2_conf.ini being missing, please copy neutron/plugins/ml2/ml2_conf.ini.sample to /etc/neutron/plugins/ml2/ml2_conf.ini and stack again.
LBaaS v2 Driver LBaaS v2 Driver
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
@ -297,14 +318,13 @@ Configure the service provider::
[DEFAULT] [DEFAULT]
api_extensions_path = $DEST/neutron-lbaas/neutron_lbaas/extensions api_extensions_path = $DEST/neutron-lbaas/neutron_lbaas/extensions
FWaaS (V2) Driver FWaaS (V2) Driver
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
Add neutron-fwaas repo as an external repository and configure following flags in ``local.conf``:: Add neutron-fwaas repo as an external repository and configure following flags in ``local.conf``::
[[local|localrc]] [[local|localrc]]
ENABLED_SERVICES+=,q-fwaas-v2 enable_service q-fwaas-v2
Q_SERVICE_PLUGIN_CLASSES+=,vmware_nsxtvd_fwaasv2 Q_SERVICE_PLUGIN_CLASSES+=,vmware_nsxtvd_fwaasv2
[[post-config|$NEUTRON_CONF]] [[post-config|$NEUTRON_CONF]]
@ -317,6 +337,8 @@ Add neutron-fwaas repo as an external repository and configure following flags i
[service_providers] [service_providers]
service_provider = FIREWALL_V2:fwaas_db:neutron_fwaas.services.firewall.service_drivers.agents.agents.FirewallAgentDriver:default service_provider = FIREWALL_V2:fwaas_db:neutron_fwaas.services.firewall.service_drivers.agents.agents.FirewallAgentDriver:default
Note - if devstack fails due to ml2_conf.ini being missing, please copy neutron/plugins/ml2/ml2_conf.ini.sample to /etc/neutron/plugins/ml2/ml2_conf.ini and stack again.
L2GW Driver L2GW Driver
~~~~~~~~~~~ ~~~~~~~~~~~

View File

@ -0,0 +1,6 @@
---
prelude: >
The NSX-V plugin can suppport FWaaS-V2 for setting router edges firewall rules.
features:
- |
The NSX-V plugin can suppport FWaaS-V2 for setting router edges firewall rules.

View File

@ -36,7 +36,7 @@ neutron.core_plugins =
vmware_dvs = vmware_nsx.plugin:NsxDvsPlugin vmware_dvs = vmware_nsx.plugin:NsxDvsPlugin
vmware_nsxtvd = vmware_nsx.plugin:NsxTVDPlugin vmware_nsxtvd = vmware_nsx.plugin:NsxTVDPlugin
firewall_drivers = firewall_drivers =
vmware_nsxv3_edge = vmware_nsx.services.fwaas.nsx_v3.edge_fwaas_driver_v1:EdgeFwaasV3DriverV1 vmware_nsxv_edge_v2 = vmware_nsx.services.fwaas.nsx_v.edge_fwaas_driver_v2:EdgeFwaasVDriverV2
vmware_nsxv3_edge_v2 = vmware_nsx.services.fwaas.nsx_v3.edge_fwaas_driver_v2:EdgeFwaasV3DriverV2 vmware_nsxv3_edge_v2 = vmware_nsx.services.fwaas.nsx_v3.edge_fwaas_driver_v2:EdgeFwaasV3DriverV2
vmware_nsxtvd_edge_v2 = vmware_nsx.services.fwaas.nsx_tv.edge_fwaas_driver_v2:EdgeFwaasTVDriverV2 vmware_nsxtvd_edge_v2 = vmware_nsx.services.fwaas.nsx_tv.edge_fwaas_driver_v2:EdgeFwaasTVDriverV2
neutron.service_plugins = neutron.service_plugins =

View File

@ -144,6 +144,8 @@ from vmware_nsx.plugins.nsx_v.vshield import edge_utils
from vmware_nsx.plugins.nsx_v.vshield import securitygroup_utils from vmware_nsx.plugins.nsx_v.vshield import securitygroup_utils
from vmware_nsx.plugins.nsx_v.vshield import vcns_driver from vmware_nsx.plugins.nsx_v.vshield import vcns_driver
from vmware_nsx.services.flowclassifier.nsx_v import utils as fc_utils from vmware_nsx.services.flowclassifier.nsx_v import utils as fc_utils
from vmware_nsx.services.fwaas.common import utils as fwaas_utils
from vmware_nsx.services.fwaas.nsx_v import fwaas_callbacks_v2
from vmware_nsx.services.lbaas.nsx_v.implementation import healthmon_mgr from vmware_nsx.services.lbaas.nsx_v.implementation import healthmon_mgr
from vmware_nsx.services.lbaas.nsx_v.implementation import l7policy_mgr from vmware_nsx.services.lbaas.nsx_v.implementation import l7policy_mgr
from vmware_nsx.services.lbaas.nsx_v.implementation import l7rule_mgr from vmware_nsx.services.lbaas.nsx_v.implementation import l7rule_mgr
@ -329,9 +331,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# Make sure starting rpc listeners (for QoS and other agents) # Make sure starting rpc listeners (for QoS and other agents)
# will happen only once # will happen only once
self.start_rpc_listeners_called = False self.start_rpc_listeners_called = False
self.fwaas_callbacks = None
# Init the FWaaS support
self._init_fwaas()
# Service insertion driver register # Service insertion driver register
self._si_handler = fc_utils.NsxvServiceInsertionHandler(self) self._si_handler = fc_utils.NsxvServiceInsertionHandler(self)
@ -412,6 +412,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
self.octavia_listener = octavia_listener.NSXOctaviaListener( self.octavia_listener = octavia_listener.NSXOctaviaListener(
**octavia_objects) **octavia_objects)
# Init the FWaaS support
self._init_fwaas()
self.init_is_complete = True self.init_is_complete = True
def _get_octavia_objects(self): def _get_octavia_objects(self):
@ -497,8 +500,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
def _init_fwaas(self): def _init_fwaas(self):
# Bind FWaaS callbacks to the driver # Bind FWaaS callbacks to the driver
#TODO(asarfaty): waiting for FWaaS v2 support if fwaas_utils.is_fwaas_v2_plugin_enabled():
self.fwaas_callbacks = None LOG.info("NSXv FWaaS v2 plugin enabled")
self.fwaas_callbacks = fwaas_callbacks_v2.NsxvFwaasCallbacksV2()
def _create_security_group_container(self): def _create_security_group_container(self):
name = "OpenStack Security Group container" name = "OpenStack Security Group container"
@ -3913,9 +3917,29 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
context, router_id, interface_info) context, router_id, interface_info)
def remove_router_interface(self, context, router_id, interface_info): def remove_router_interface(self, context, router_id, interface_info):
# Get the router interface port id
if self.fwaas_callbacks:
port_id = interface_info.get('port_id')
if not port_id:
subnet_id = interface_info['subnet_id']
subnet = self._get_subnet(context, subnet_id)
rport_qry = context.session.query(models_v2.Port)
ports = rport_qry.filter_by(
device_id=router_id,
device_owner=l3_db.DEVICE_OWNER_ROUTER_INTF,
network_id=subnet['network_id'])
for p in ports:
if p['fixed_ips'][0]['subnet_id'] == subnet_id:
port_id = p['id']
break
router_driver = self._find_router_driver(context, router_id) router_driver = self._find_router_driver(context, router_id)
return router_driver.remove_router_interface( result = router_driver.remove_router_interface(
context, router_id, interface_info) context, router_id, interface_info)
# inform the FWaaS that interface port was removed
if self.fwaas_callbacks and port_id:
self.fwaas_callbacks.delete_port(context, port_id)
return result
def _get_floatingips_by_router(self, context, router_id): def _get_floatingips_by_router(self, context, router_id):
fip_qry = context.session.query(l3_db_models.FloatingIP) fip_qry = context.session.query(l3_db_models.FloatingIP)
@ -4015,35 +4039,22 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
router_db is the neutron router structure router_db is the neutron router structure
router_id is the id of the actual router that will be updated on router_id is the id of the actual router that will be updated on
the NSX (in case of distributed router it can be plr or tlr) the NSX (in case of distributed router it can be plr or tlr)
This is just a wrapper of update_router_firewall
""" """
if not router_id: if not router_id:
router_id = router_db['id'] router_id = router_db['id']
# Add fw rules if FWaaS is enabled self.update_router_firewall(context, router_id, router_db)
# in case of a distributed-router:
# router['id'] is the id of the neutron router (=tlr)
# and router_id is the plr/tlr (the one that is being updated)
fwaas_rules = None
if (self.fwaas_callbacks and
self.fwaas_callbacks.should_apply_firewall_to_router(
context, router_db, router_id)):
fwaas_rules = self.fwaas_callbacks.get_fwaas_rules_for_router(
context, router_db['id'])
self.update_router_firewall(context, router_id, router_db, def update_router_firewall(self, context, router_id, router_db):
fwaas_rules=fwaas_rules)
def update_router_firewall(self, context, router_id, router_db,
fwaas_rules=None):
"""Recreate all rules in the router edge firewall """Recreate all rules in the router edge firewall
router_db is the neutron router structure router_db is the neutron router structure
router_id is the id of the actual router that will be updated on router_id is the id of the actual router that will be updated on
the NSX (in case of distributed router it can be plr or tlr) the NSX (in case of distributed router it can be plr or tlr)
if fwaas_rules is not none - this router is attached to a firewall
""" """
fw_rules = [] fw_rules = []
router_with_firewall = True if fwaas_rules is not None else False
edge_id = self._get_edge_id_by_rtr_id(context, router_id) edge_id = self._get_edge_id_by_rtr_id(context, router_id)
# Add FW rule/s to open subnets firewall flows and static routes # Add FW rule/s to open subnets firewall flows and static routes
@ -4056,33 +4067,41 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
if self.metadata_proxy_handler: if self.metadata_proxy_handler:
fw_rules += nsx_v_md_proxy.get_router_fw_rules() fw_rules += nsx_v_md_proxy.get_router_fw_rules()
# Add FWaaS rules # Add FWaaS rules if FWaaS is enabled
if router_with_firewall and fwaas_rules: if (self.fwaas_callbacks and
fw_rules += fwaas_rules self.fwaas_callbacks.should_apply_firewall_to_router(
context, router_db, router_id)):
fwaas_rules = self.fwaas_callbacks.get_fwaas_rules_for_router(
context, router_db['id'], edge_id)
if fwaas_rules:
fw_rules += fwaas_rules
if not router_with_firewall: # The rules added from here forward are relevant only for interface
dnat_rule = self._get_dnat_fw_rule(context, router_db) # ports without fwaas firewall group
if dnat_rule: # To allow this traffic on interfaces with firewall group, the user
fw_rules.append(dnat_rule) # should add specific rules.
dnat_rule = self._get_dnat_fw_rule(context, router_db)
if dnat_rule:
fw_rules.append(dnat_rule)
# Add rule for not NAT-ed allocation pools # Add rule for not NAT-ed allocation pools
alloc_pool_rule = self._get_allocation_pools_fw_rule( alloc_pool_rule = self._get_allocation_pools_fw_rule(
context, router_db) context, router_db)
if alloc_pool_rule: if alloc_pool_rule:
fw_rules.append(alloc_pool_rule) fw_rules.append(alloc_pool_rule)
# Add no-snat rules # Add no-snat rules
nosnat_fw_rules = self._get_nosnat_subnets_fw_rules( nosnat_fw_rules = self._get_nosnat_subnets_fw_rules(
context, router_db) context, router_db)
fw_rules.extend(nosnat_fw_rules) fw_rules.extend(nosnat_fw_rules)
vpn_plugin = directory.get_plugin(plugin_const.VPN) vpn_plugin = directory.get_plugin(plugin_const.VPN)
if vpn_plugin: if vpn_plugin:
vpn_driver = vpn_plugin.drivers[vpn_plugin.default_provider] vpn_driver = vpn_plugin.drivers[vpn_plugin.default_provider]
vpn_rules = ( vpn_rules = (
vpn_driver._generate_ipsecvpn_firewall_rules( vpn_driver._generate_ipsecvpn_firewall_rules(
self.plugin_type(), context, edge_id=edge_id)) self.plugin_type(), context, edge_id=edge_id))
fw_rules.extend(vpn_rules) fw_rules.extend(vpn_rules)
# Get the load balancer rules in case they are refreshed # Get the load balancer rules in case they are refreshed
# (relevant only for older LB that are still on the router edge) # (relevant only for older LB that are still on the router edge)
@ -4102,11 +4121,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
fw = {'firewall_rule_list': fw_rules} fw = {'firewall_rule_list': fw_rules}
try: try:
# If we have a firewall we shouldn't add the default edge_utils.update_firewall(self.nsx_v, context, router_id, fw)
# allow-external rule
allow_external = False if router_with_firewall else True
edge_utils.update_firewall(self.nsx_v, context, router_id, fw,
allow_external=allow_external)
except vsh_exc.ResourceNotFound: except vsh_exc.ResourceNotFound:
LOG.error("Failed to update firewall for router %s", LOG.error("Failed to update firewall for router %s",
router_id) router_id)

View File

@ -2577,7 +2577,8 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
relay_target = [] relay_target = []
if self.fwaas_callbacks: if self.fwaas_callbacks:
relay_target = (self.fwaas_callbacks.fwaas_driver. relay_target = (self.fwaas_callbacks.fwaas_driver.
translate_addresses_to_target(set(relay_servers))) translate_addresses_to_target(set(relay_servers),
self.plugin_type()))
dhcp_services = self._get_port_relay_services() dhcp_services = self._get_port_relay_services()

View File

@ -1,4 +1,4 @@
# Copyright 2017 VMware, Inc. # Copyright 2018 VMware, Inc.
# All Rights Reserved # All Rights Reserved
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -48,22 +48,20 @@ class NsxFwaasCallbacksV2(firewall_l3_agent_v2.L3WithFWaaS):
neutron_conf.agent_mode = 'nsx' neutron_conf.agent_mode = 'nsx'
super(NsxFwaasCallbacksV2, self).__init__(conf=neutron_conf) super(NsxFwaasCallbacksV2, self).__init__(conf=neutron_conf)
self.agent_api = DummyAgentApi() self.agent_api = DummyAgentApi()
self._core_plugin = None self.core_plugin = self._get_core_plugin()
@property @property
def plugin_type(self): def plugin_type(self):
pass pass
@property def _get_core_plugin(self):
def core_plugin(self): """Get the NSX core plugin"""
"""Get the NSX-V3 core plugin""" core_plugin = directory.get_plugin()
if not self._core_plugin: if core_plugin.is_tvd_plugin():
self._core_plugin = directory.get_plugin() # get the plugin that match this driver
if self._core_plugin.is_tvd_plugin(): core_plugin = core_plugin.get_plugin_by_type(
# get the plugin that match this driver self.plugin_type)
self._core_plugin = self._core_plugin.get_plugin_by_type( return core_plugin
self.plugin_type)
return self._core_plugin
# Override functions using the agent_api that is not used by our plugin # Override functions using the agent_api that is not used by our plugin
def _get_firewall_group_ports(self, context, firewall_group, def _get_firewall_group_ports(self, context, firewall_group,
@ -203,3 +201,33 @@ class NsxFwaasCallbacksV2(firewall_l3_agent_v2.L3WithFWaaS):
port_id=port_id).first() port_id=port_id).first()
if entry: if entry:
return entry.firewall_group_id return entry.firewall_group_id
def should_apply_firewall_to_router(self, context, router_id):
"""Return True if there are FWaaS rules that are attached to an
interface of the given router.
"""
if not self.fwaas_enabled:
return False
ctx = context.elevated()
router_interfaces = self.core_plugin._get_router_interfaces(
ctx, router_id)
for port in router_interfaces:
fwg_id = self._get_port_firewall_group_id(ctx, port['id'])
if fwg_id:
# check the state of this firewall group
fwg = self._get_fw_group_from_plugin(ctx, fwg_id)
if fwg is not None:
if fwg.get('status') not in (nl_constants.ERROR,
nl_constants.PENDING_DELETE):
# Found a router interface port with rules
return True
return False
def delete_port(self, context, port_id):
# Mark the FW group as inactive if this is the last port
fwg = self.get_port_fwg(context, port_id)
if (fwg and fwg.get('status') == nl_constants.ACTIVE and
len(fwg.get('ports', [])) <= 1):
self.fwplugin_rpc.set_firewall_group_status(
context, fwg['id'], nl_constants.INACTIVE)

View File

@ -0,0 +1,93 @@
# Copyright 2017 VMware, Inc.
# All Rights Reserved
#
# 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.
import abc
from oslo_log import helpers as log_helpers
from oslo_log import log as logging
from neutron_lib.exceptions import firewall_v2 as exceptions
try:
from neutron_fwaas.services.firewall.service_drivers.agents.drivers \
import fwaas_base
except ImportError:
# FWaaS project no found
from vmware_nsx.services.fwaas.common import fwaas_mocks \
as fwaas_base
LOG = logging.getLogger(__name__)
class EdgeFwaasDriverBaseV2(fwaas_base.FwaasDriverBase):
"""NSX Base driver for Firewall As A Service - V2."""
def __init__(self, driver_name):
super(EdgeFwaasDriverBaseV2, self).__init__()
self.driver_name = driver_name
@log_helpers.log_method_call
def create_firewall_group(self, agent_mode, apply_list, firewall_group):
"""Create the Firewall with a given policy. """
self._validate_firewall_group(firewall_group)
self._update_backend_routers(apply_list, firewall_group['id'])
@log_helpers.log_method_call
def update_firewall_group(self, agent_mode, apply_list, firewall_group):
"""Remove previous policy and apply the new policy."""
self._validate_firewall_group(firewall_group)
self._update_backend_routers(apply_list, firewall_group['id'])
@log_helpers.log_method_call
def delete_firewall_group(self, agent_mode, apply_list, firewall_group):
"""Delete firewall.
Removes rules created by this instance from the backend firewall
And add the default allow rule.
"""
self._update_backend_routers(apply_list, firewall_group['id'])
@log_helpers.log_method_call
def apply_default_policy(self, agent_mode, apply_list, firewall_group):
"""Apply the default policy (deny all).
The backend firewall always has this policy (=deny all) as default,
so we only need to delete the current rules.
"""
self._update_backend_routers(apply_list, firewall_group['id'])
@abc.abstractmethod
def _update_backend_routers(self, apply_list, fwg_id):
"""Update all the affected router on the backend"""
pass
def _validate_firewall_group(self, firewall_group):
"""Validate the rules in the firewall group"""
for rule in firewall_group['egress_rule_list']:
if rule.get('source_ip_address'):
# this rule cannot be used as egress rule
LOG.error("Rule %(id)s cannot be used in an egress "
"policy because it has a source",
{'id': rule['id']})
raise exceptions.FirewallInternalDriverError(
driver=self.driver_name)
for rule in firewall_group['ingress_rule_list']:
if rule.get('destination_ip_address'):
# this rule cannot be used as ingress rule
LOG.error("Rule %(id)s cannot be used in an ingress "
"policy because it has a destination",
{'id': rule['id']})
raise exceptions.FirewallInternalDriverError(
driver=self.driver_name)

View File

@ -20,6 +20,7 @@ from neutron_lib.exceptions import firewall_v2 as exceptions
from vmware_nsx.extensions import projectpluginmap from vmware_nsx.extensions import projectpluginmap
from vmware_nsx.plugins.nsx import utils as tvd_utils from vmware_nsx.plugins.nsx import utils as tvd_utils
from vmware_nsx.services.fwaas.nsx_v import edge_fwaas_driver_v2 as v_driver
from vmware_nsx.services.fwaas.nsx_v3 import edge_fwaas_driver_v2 as t_driver from vmware_nsx.services.fwaas.nsx_v3 import edge_fwaas_driver_v2 as t_driver
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -36,15 +37,13 @@ except ImportError:
class EdgeFwaasTVDriverV2(fwaas_base_v2.FwaasDriverBase): class EdgeFwaasTVDriverV2(fwaas_base_v2.FwaasDriverBase):
"""NSX-TV driver for Firewall As A Service - V2. """NSX-TV driver for Firewall As A Service - V2.
This driver is just a wrapper calling the relevant nsx-v3 driver
""" """
def __init__(self): def __init__(self):
super(EdgeFwaasTVDriverV2, self).__init__() super(EdgeFwaasTVDriverV2, self).__init__()
self.driver_name = FWAAS_DRIVER_NAME self.driver_name = FWAAS_DRIVER_NAME
# supported drivers (Only NSX-T): # supported drivers:
self.drivers = {} self.drivers = {}
try: try:
self.drivers[projectpluginmap.NsxPlugins.NSX_T] = ( self.drivers[projectpluginmap.NsxPlugins.NSX_T] = (
@ -53,10 +52,20 @@ class EdgeFwaasTVDriverV2(fwaas_base_v2.FwaasDriverBase):
LOG.warning("EdgeFwaasTVDriverV2 failed to initialize the NSX-T " LOG.warning("EdgeFwaasTVDriverV2 failed to initialize the NSX-T "
"driver") "driver")
self.drivers[projectpluginmap.NsxPlugins.NSX_T] = None self.drivers[projectpluginmap.NsxPlugins.NSX_T] = None
try:
self.drivers[projectpluginmap.NsxPlugins.NSX_V] = (
v_driver.EdgeFwaasVDriverV2())
except Exception:
LOG.warning("EdgeFwaasTVDriverV2 failed to initialize the NSX-V "
"driver")
self.drivers[projectpluginmap.NsxPlugins.NSX_V] = None
def get_T_driver(self): def get_T_driver(self):
return self.drivers[projectpluginmap.NsxPlugins.NSX_T] return self.drivers[projectpluginmap.NsxPlugins.NSX_T]
def get_V_driver(self):
return self.drivers[projectpluginmap.NsxPlugins.NSX_V]
def _get_driver_for_project(self, project): def _get_driver_for_project(self, project):
plugin_type = tvd_utils.get_tvd_plugin_type_for_project(project) plugin_type = tvd_utils.get_tvd_plugin_type_for_project(project)
if not self.drivers.get(plugin_type): if not self.drivers.get(plugin_type):
@ -87,8 +96,12 @@ class EdgeFwaasTVDriverV2(fwaas_base_v2.FwaasDriverBase):
d = self._get_driver_for_project(firewall_group['tenant_id']) d = self._get_driver_for_project(firewall_group['tenant_id'])
return d.apply_default_policy(agent_mode, apply_list, firewall_group) return d.apply_default_policy(agent_mode, apply_list, firewall_group)
def translate_addresses_to_target(self, cidrs, fwaas_rule_id=None): def translate_addresses_to_target(self, cidrs, plugin_type,
fwaas_rule_id=None):
# This api is called directly from the core plugin # This api is called directly from the core plugin
# Assuming nsx-T as it is the only one supported now. if not self.drivers.get(plugin_type):
return self.get_T_driver().translate_addresses_to_target( LOG.error("%s has no support for plugin %s",
cidrs, fwaas_rule_id=fwaas_rule_id) self.driver_name, plugin_type)
else:
return self.drivers[plugin_type].translate_addresses_to_target(
cidrs, fwaas_rule_id=fwaas_rule_id)

View File

@ -0,0 +1,142 @@
# Copyright 2018 VMware, Inc.
# All Rights Reserved
#
# 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 neutron_lib import context as n_context
from oslo_log import log as logging
from neutron_lib.exceptions import firewall_v2 as exceptions
from neutron_lib.plugins import directory
from vmware_nsx.common import locking
from vmware_nsx.extensions import projectpluginmap
from vmware_nsx.plugins.nsx_v.vshield import edge_utils
from vmware_nsx.services.fwaas.common import fwaas_driver_base
LOG = logging.getLogger(__name__)
FWAAS_DRIVER_NAME = 'Fwaas V2 NSX-V driver'
class EdgeFwaasVDriverV2(fwaas_driver_base.EdgeFwaasDriverBaseV2):
"""NSX-V driver for Firewall As A Service - V2."""
def __init__(self):
super(EdgeFwaasVDriverV2, self).__init__(FWAAS_DRIVER_NAME)
self._core_plugin = None
@property
def core_plugin(self):
"""Get the NSX-V core plugin"""
if not self._core_plugin:
self._core_plugin = directory.get_plugin()
if self._core_plugin.is_tvd_plugin():
self._core_plugin = self._core_plugin.get_plugin_by_type(
projectpluginmap.NsxPlugins.NSX_V)
if not self._core_plugin:
# The NSX-V plugin was not initialized
return
# make sure plugin init was completed
if not self._core_plugin.init_is_complete:
self._core_plugin.init_complete(None, None, {})
return self._core_plugin
def should_apply_firewall_to_router(self, router_data,
raise_exception=True):
"""Return True if the firewall rules allowed to be added the router
Return False in those cases:
- router without an external gateway (rule may be added later when
there is a gateway)
Raise an exception if the router is unsupported
(and raise_exception is True):
- shared router (not supported)
- md proxy router (not supported)
"""
if (not router_data.get('distributed') and
router_data.get('router_type') == 'shared'):
LOG.error("Cannot apply firewall to shared router %s",
router_data['id'])
if raise_exception:
raise exceptions.FirewallInternalDriverError(
driver=self.driver_name)
return False
if router_data.get('name', '').startswith('metadata_proxy_router'):
LOG.error("Cannot apply firewall to the metadata proxy router %s",
router_data['id'])
if raise_exception:
raise exceptions.FirewallInternalDriverError(
driver=self.driver_name)
return False
if not router_data.get('external_gateway_info'):
LOG.info("Cannot apply firewall to router %s with no gateway",
router_data['id'])
return False
return True
def _update_backend_routers(self, apply_list, fwg_id):
"""Update all the affected routers on the backend"""
LOG.info("Updating routers firewall for firewall group %s", fwg_id)
context = n_context.get_admin_context()
routers = set()
routers_mapping = {}
# the apply_list is a list of tuples: routerInfo, port-id
for router_info, port_id in apply_list:
# Skip dummy entries that were added only to avoid errors
if isinstance(router_info, str):
continue
# Skip unsupported routers
if not self.should_apply_firewall_to_router(router_info.router):
continue
lookup_id = None
router_id = router_info.router_id
if router_info.router.get('distributed'):
# Distributed router (need to update the plr edge)
lookup_id = self.core_plugin.edge_manager.get_plr_by_tlr_id(
context, router_id)
else:
# Exclusive router
lookup_id = router_id
if lookup_id:
# look for the edge id in the DB
edge_id = edge_utils.get_router_edge_id(context, lookup_id)
if edge_id:
routers_mapping[router_id] = {'edge_id': edge_id,
'lookup_id': lookup_id}
routers.add(router_id)
# update each router once using the core plugin
for router_id in routers:
router_db = self.core_plugin._get_router(context, router_id)
edge_id = routers_mapping[router_id]['edge_id']
LOG.info("Updating FWaaS rules for router %s on edge %s",
router_id, edge_id)
router_lookup_id = routers_mapping[router_id]['lookup_id']
try:
with locking.LockManager.get_lock(str(edge_id)):
self.core_plugin.update_router_firewall(
context, router_lookup_id, router_db)
except Exception as e:
# catch known library exceptions and raise Fwaas generic
# exception
LOG.error("Failed to update firewall rules on edge "
"%(edge_id)s for router %(rtr)s: %(e)s",
{'e': e, 'rtr': router_id, 'edge_id': edge_id})
raise exceptions.FirewallInternalDriverError(
driver=self.driver_name)

View File

@ -0,0 +1,167 @@
# Copyright 2018 VMware, Inc.
# All Rights Reserved
#
# 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 oslo_log import log as logging
from vmware_nsx.db import nsxv_db
from vmware_nsx.extensions import projectpluginmap
from vmware_nsx.plugins.nsx_v.vshield import edge_firewall_driver
from vmware_nsx.services.fwaas.common import fwaas_callbacks_v2 as \
com_callbacks
from vmware_nsx.services.fwaas.nsx_tv import edge_fwaas_driver_v2 as tv_driver
LOG = logging.getLogger(__name__)
RULE_NAME_PREFIX = 'Fwaas-'
class NsxvFwaasCallbacksV2(com_callbacks.NsxFwaasCallbacksV2):
"""NSX-V RPC callbacks for Firewall As A Service - V2."""
def __init__(self):
super(NsxvFwaasCallbacksV2, self).__init__()
# update the fwaas driver in case of TV plugin
self.internal_driver = None
if self.fwaas_enabled:
if self.fwaas_driver.driver_name == tv_driver.FWAAS_DRIVER_NAME:
self.internal_driver = self.fwaas_driver.get_V_driver()
else:
self.internal_driver = self.fwaas_driver
@property
def plugin_type(self):
return projectpluginmap.NsxPlugins.NSX_V
def should_apply_firewall_to_router(self, context, router, router_id):
"""Return True if the FWaaS rules should be added to this router."""
# in case of a distributed-router:
# router['id'] is the id of the neutron router (=tlr)
# and router_id is the plr/tlr (the one that is being updated)
# First check if there are rules attached to this router
if not super(NsxvFwaasCallbacksV2,
self).should_apply_firewall_to_router(
context, router['id']):
return False
# get all the relevant router info
# ("router" does not have all the fields)
ctx_elevated = context.elevated()
router_data = self.core_plugin.get_router(ctx_elevated, router['id'])
if not router_data:
LOG.error("Couldn't read router %s data", router['id'])
return False
if router_data.get('distributed'):
if router_id == router['id']:
# Do not add firewall rules on the tlr router.
return False
# Check if the FWaaS driver supports this router
if not self.internal_driver.should_apply_firewall_to_router(
router_data, raise_exception=False):
return False
return True
def get_fwaas_rules_for_router(self, context, router_id, edge_id):
"""Return the list of (translated) FWaaS rules for this router."""
ctx_elevated = context.elevated()
router_interfaces = self.core_plugin._get_router_interfaces(
ctx_elevated, router_id)
fw_rules = []
# Add firewall rules per port attached to a firewall group
for port in router_interfaces:
fwg = self.get_port_fwg(ctx_elevated, port['id'])
if fwg:
# get the interface vnic
edge_vnic_bind = nsxv_db.get_edge_vnic_binding(
context.session, edge_id, port['network_id'])
vnic_id = 'vnic-index-%s' % edge_vnic_bind.vnic_index
# Add the FWaaS rules for this port
fw_rules.extend(
self.get_port_translated_rules(vnic_id, fwg))
return fw_rules
def get_port_translated_rules(self, vnic_id, firewall_group):
"""Return the list of translated rules per port
Ingress/Egress firewall rules + default ingress/egress drop
"""
port_rules = []
logged = False
# Add the firewall group ingress/egress rules only if the fw is up
if firewall_group['admin_state_up']:
port_rules.extend(self.translate_rules(
firewall_group['ingress_rule_list'],
replace_dest=vnic_id,
logged=logged,
is_ingress=True))
port_rules.extend(self.translate_rules(
firewall_group['egress_rule_list'],
replace_src=vnic_id,
logged=logged,
is_ingress=False))
# Add ingress/egress block rules for this port
port_rules.extend([
{'name': "Block port ingress",
'action': edge_firewall_driver.FWAAS_DENY,
'destination_vnic_groups': [vnic_id],
'logged': logged},
{'name': "Block port egress",
'action': edge_firewall_driver.FWAAS_DENY,
'source_vnic_groups': [vnic_id],
'logged': logged}])
return port_rules
def translate_rules(self, fwaas_rules, replace_dest=None, replace_src=None,
logged=False, is_ingress=True):
translated_rules = []
for rule in fwaas_rules:
if not rule['enabled']:
# skip disabled rules
continue
# Make sure the rule has a name, and it starts with the prefix
# (backend max name length is 30)
if rule.get('name'):
rule['name'] = RULE_NAME_PREFIX + rule['name']
else:
rule['name'] = RULE_NAME_PREFIX + rule['id']
rule['name'] = rule['name'][:30]
if rule.get('id'):
# update rules ID to prevent DB duplications in
# NsxvEdgeFirewallRuleBinding
if is_ingress:
rule['id'] = ('ingress-%s' % rule['id'])[:36]
else:
rule['id'] = ('egress-%s' % rule['id'])[:36]
# source & destination should be lists
if replace_dest:
rule['destination_vnic_groups'] = [replace_dest]
elif rule.get('destination_ip_address'):
rule['destination_ip_address'] = [
rule['destination_ip_address']]
if replace_src:
rule['source_vnic_groups'] = [replace_src]
elif rule.get('source_ip_address'):
rule['source_ip_address'] = [rule['source_ip_address']]
if logged:
rule['logged'] = True
translated_rules.append(rule)
return translated_rules

View File

@ -23,27 +23,21 @@ from neutron_lib.plugins import directory
from oslo_log import log as logging from oslo_log import log as logging
from vmware_nsx.extensions import projectpluginmap from vmware_nsx.extensions import projectpluginmap
from vmware_nsx.services.fwaas.common import fwaas_driver_base
from vmware_nsxlib.v3 import nsx_constants as consts from vmware_nsxlib.v3 import nsx_constants as consts
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
RULE_NAME_PREFIX = 'Fwaas-' RULE_NAME_PREFIX = 'Fwaas-'
DEFAULT_RULE_NAME = 'Default LR Layer3 Rule' DEFAULT_RULE_NAME = 'Default LR Layer3 Rule'
try:
from neutron_fwaas.services.firewall.service_drivers.agents.drivers \
import fwaas_base
except ImportError:
# FWaaS project no found
from vmware_nsx.services.fwaas.common import fwaas_mocks \
as fwaas_base
#TODO(asarfaty): this base class now serves only 1 driver and can be merged
class CommonEdgeFwaasV3Driver(fwaas_base.FwaasDriverBase): # with it
class CommonEdgeFwaasV3Driver(fwaas_driver_base.EdgeFwaasDriverBaseV2):
"""Base class for NSX-V3 driver for Firewall As A Service - V1 & V2.""" """Base class for NSX-V3 driver for Firewall As A Service - V1 & V2."""
def __init__(self, driver_exception, driver_name): def __init__(self, driver_exception, driver_name):
super(CommonEdgeFwaasV3Driver, self).__init__() super(CommonEdgeFwaasV3Driver, self).__init__(driver_name)
self.driver_name = driver_name
self.backend_support = True self.backend_support = True
self.driver_exception = driver_exception self.driver_exception = driver_exception
registry.subscribe( registry.subscribe(
@ -139,7 +133,8 @@ class CommonEdgeFwaasV3Driver(fwaas_base.FwaasDriverBase):
cidr, cidr,
consts.IPV6 if net.version == 6 else consts.IPV4) consts.IPV6 if net.version == 6 else consts.IPV4)
def translate_addresses_to_target(self, cidrs, fwaas_rule_id=None): def translate_addresses_to_target(self, cidrs, plugin_type,
fwaas_rule_id=None):
translated_cidrs = [] translated_cidrs = []
for ip in cidrs: for ip in cidrs:
res = self._translate_cidr(ip, fwaas_rule_id) res = self._translate_cidr(ip, fwaas_rule_id)

View File

@ -14,7 +14,6 @@
# under the License. # under the License.
from neutron_lib import context as n_context from neutron_lib import context as n_context
from oslo_log import helpers as log_helpers
from oslo_log import log as logging from oslo_log import log as logging
from neutron_lib.exceptions import firewall_v2 as exceptions from neutron_lib.exceptions import firewall_v2 as exceptions
@ -35,36 +34,6 @@ class EdgeFwaasV3DriverV2(base_driver.CommonEdgeFwaasV3Driver):
super(EdgeFwaasV3DriverV2, self).__init__(exception_cls, super(EdgeFwaasV3DriverV2, self).__init__(exception_cls,
FWAAS_DRIVER_NAME) FWAAS_DRIVER_NAME)
@log_helpers.log_method_call
def create_firewall_group(self, agent_mode, apply_list, firewall_group):
"""Create the Firewall with a given policy. """
self._validate_firewall_group(firewall_group)
self._update_backend_routers(apply_list, firewall_group['id'])
@log_helpers.log_method_call
def update_firewall_group(self, agent_mode, apply_list, firewall_group):
"""Remove previous policy and apply the new policy."""
self._validate_firewall_group(firewall_group)
self._update_backend_routers(apply_list, firewall_group['id'])
@log_helpers.log_method_call
def delete_firewall_group(self, agent_mode, apply_list, firewall_group):
"""Delete firewall.
Removes rules created by this instance from the backend firewall
And add the default allow rule.
"""
self._update_backend_routers(apply_list, firewall_group['id'])
@log_helpers.log_method_call
def apply_default_policy(self, agent_mode, apply_list, firewall_group):
"""Apply the default policy (deny all).
The backend firewall always has this policy (=deny all) as default,
so we only need to delete the current rules.
"""
self._update_backend_routers(apply_list, firewall_group['id'])
def _update_backend_routers(self, apply_list, fwg_id): def _update_backend_routers(self, apply_list, fwg_id):
"""Update all the affected router on the backend""" """Update all the affected router on the backend"""
self.validate_backend_version() self.validate_backend_version()
@ -121,22 +90,3 @@ class EdgeFwaasV3DriverV2(base_driver.CommonEdgeFwaasV3Driver):
'direction': 'OUT'}]) 'direction': 'OUT'}])
return port_rules return port_rules
def _validate_firewall_group(self, firewall_group):
"""Validate the rules in the firewall group"""
for rule in firewall_group['egress_rule_list']:
if rule.get('source_ip_address'):
# this rule cannot be used as egress rule
LOG.error("Rule %(id)s cannot be used in an egress "
"policy because it has a source",
{'id': rule['id']})
raise exceptions.FirewallInternalDriverError(
driver=FWAAS_DRIVER_NAME)
for rule in firewall_group['ingress_rule_list']:
if rule.get('destination_ip_address'):
# this rule cannot be used as ingress rule
LOG.error("Rule %(id)s cannot be used in an ingress "
"policy because it has a destination",
{'id': rule['id']})
raise exceptions.FirewallInternalDriverError(
driver=FWAAS_DRIVER_NAME)

View File

@ -0,0 +1,288 @@
# Copyright 2018 VMware, Inc.
# All Rights Reserved
#
# 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.
import copy
import mock
from neutron_lib.exceptions import firewall_v2 as exceptions
from neutron_lib.plugins import directory
from vmware_nsx.db import nsxv_models
from vmware_nsx.plugins.nsx_v.vshield import edge_firewall_driver
from vmware_nsx.plugins.nsx_v.vshield import edge_utils
from vmware_nsx.services.fwaas.nsx_v import edge_fwaas_driver_v2
from vmware_nsx.services.fwaas.nsx_v import fwaas_callbacks_v2
from vmware_nsx.tests.unit.nsx_v import test_plugin as test_v_plugin
FAKE_FW_ID = 'fake_fw_uuid'
FAKE_ROUTER_ID = 'fake_rtr_uuid'
FAKE_PORT_ID = 'fake_port_uuid'
FAKE_NET_ID = 'fake_net_uuid'
FAKE_DB_OBJ = nsxv_models.NsxvEdgeVnicBinding(vnic_index='1')
class NsxvFwaasTestCase(test_v_plugin.NsxVPluginV2TestCase):
def setUp(self):
super(NsxvFwaasTestCase, self).setUp()
self.firewall = edge_fwaas_driver_v2.EdgeFwaasVDriverV2()
self.plugin = directory.get_plugin()
self.plugin.fwaas_callbacks = fwaas_callbacks_v2.\
NsxvFwaasCallbacksV2()
self.plugin.fwaas_callbacks.fwaas_enabled = True
self.plugin.fwaas_callbacks.fwaas_driver = self.firewall
self.plugin.fwaas_callbacks.internal_driver = self.firewall
self.plugin.init_is_complete = True
self.plugin.metadata_proxy_handler = None
# Start some mocks
self.router = {'id': FAKE_ROUTER_ID,
'external_gateway_info': {'network_id': 'external'}}
mock.patch.object(self.plugin, '_get_router',
return_value=self.router).start()
mock.patch.object(self.plugin, 'get_router',
return_value=self.router).start()
self.port = {'id': FAKE_PORT_ID, 'network_id': FAKE_NET_ID}
mock.patch.object(self.plugin, '_get_router_interfaces',
return_value=[self.port]).start()
mock.patch.object(self.plugin, 'get_port',
return_value=self.port).start()
mock.patch.object(self.plugin, '_get_subnet_fw_rules',
return_value=[]).start()
mock.patch.object(self.plugin, '_get_dnat_fw_rule',
return_value=[]).start()
mock.patch.object(self.plugin, '_get_allocation_pools_fw_rule',
return_value=[]).start()
mock.patch.object(self.plugin, '_get_nosnat_subnets_fw_rules',
return_value=[]).start()
def _fake_rules_v4(self, is_ingress=True, cidr='10.24.4.0/24'):
rule1 = {'enabled': True,
'action': 'allow',
'ip_version': 4,
'protocol': 'tcp',
'destination_port': '80',
'id': 'fake-fw-rule1',
'description': 'first rule',
'position': '0'}
rule2 = {'enabled': True,
'action': 'reject',
'ip_version': 4,
'protocol': 'tcp',
'destination_port': '22:24',
'source_port': '1:65535',
'id': 'fake-fw-rule2',
'position': '1'}
rule3 = {'enabled': True,
'action': 'deny',
'ip_version': 4,
'protocol': 'icmp',
'id': 'fake-fw-rule3',
'position': '2'}
rule4 = {'enabled': True,
'action': 'deny',
'ip_version': 4,
'id': 'fake-fw-rule4',
'position': '3'}
if is_ingress:
# source ips are allowed
rule1['source_ip_address'] = cidr
else:
# dest ips are allowed for egress rules
rule1['destination_ip_address'] = cidr
return [rule1, rule2, rule3, rule4]
def _fake_translated_rules(self, rules_list,
nsx_port_id,
is_ingress=True,
logged=False):
translated_rules = copy.copy(rules_list)
for rule in translated_rules:
if logged:
rule['logged'] = True
if is_ingress:
rule['destination_vnic_groups'] = ['vnic-index-1']
else:
rule['source_vnic_groups'] = ['vnic-index-1']
if rule.get('destination_ip_address'):
rule['destination_ip_address'] = [
rule['destination_ip_address']]
if rule.get('source_ip_address'):
rule['source_ip_address'] = [
rule['source_ip_address']]
rule['name'] = (fwaas_callbacks_v2.RULE_NAME_PREFIX +
(rule.get('name') or rule['id']))[:30]
if rule.get('id'):
if is_ingress:
rule['id'] = ('ingress-%s' % rule['id'])[:36]
else:
rule['id'] = ('egress-%s' % rule['id'])[:36]
return translated_rules
def _fake_empty_firewall_group(self):
fw_inst = {'id': FAKE_FW_ID,
'admin_state_up': True,
'tenant_id': 'tenant-uuid',
'ingress_rule_list': [],
'egress_rule_list': []}
return fw_inst
def _fake_firewall_group(self, rule_list, is_ingress=True,
admin_state_up=True):
_rule_list = copy.deepcopy(rule_list)
for rule in _rule_list:
rule['position'] = str(_rule_list.index(rule))
fw_inst = {'id': FAKE_FW_ID,
'admin_state_up': admin_state_up,
'tenant_id': 'tenant-uuid',
'ingress_rule_list': [],
'egress_rule_list': []}
if is_ingress:
fw_inst['ingress_rule_list'] = _rule_list
else:
fw_inst['egress_rule_list'] = _rule_list
return fw_inst
def _fake_firewall_group_with_admin_down(self, rule_list,
is_ingress=True):
return self._fake_firewall_group(
rule_list, is_ingress=is_ingress, admin_state_up=False)
def _fake_apply_list(self):
router_inst = self.router
router_info_inst = mock.Mock()
router_info_inst.router = router_inst
router_info_inst.router_id = FAKE_ROUTER_ID
apply_list = [(router_info_inst, FAKE_PORT_ID)]
return apply_list
def test_create_firewall_no_rules(self):
apply_list = self._fake_apply_list()
firewall = self._fake_empty_firewall_group()
with mock.patch.object(self.plugin.fwaas_callbacks, 'get_port_fwg',
return_value=firewall),\
mock.patch.object(self.plugin.fwaas_callbacks,
'_get_port_firewall_group_id',
return_value=FAKE_FW_ID),\
mock.patch.object(self.plugin.fwaas_callbacks,
'_get_fw_group_from_plugin',
return_value=firewall),\
mock.patch("vmware_nsx.db.nsxv_db.get_edge_vnic_binding",
return_value=FAKE_DB_OBJ),\
mock.patch.object(edge_utils, "update_firewall") as update_fw,\
mock.patch.object(edge_utils, 'get_router_edge_id',
return_value='edge-1'):
self.firewall.create_firewall_group('nsx', apply_list, firewall)
# expecting 2 block rules for the logical port (egress & ingress)
# and last default allow all rule
expected_rules = [
{'name': "Block port ingress",
'action': edge_firewall_driver.FWAAS_DENY,
'destination_vnic_groups': ['vnic-index-1'],
'logged': False},
{'name': "Block port egress",
'action': edge_firewall_driver.FWAAS_DENY,
'source_vnic_groups': ['vnic-index-1'],
'logged': False}]
update_fw.assert_called_once_with(
self.plugin.nsx_v, mock.ANY, FAKE_ROUTER_ID,
{'firewall_rule_list': expected_rules})
def _setup_firewall_with_rules(self, func, is_ingress=True):
apply_list = self._fake_apply_list()
rule_list = self._fake_rules_v4(is_ingress=is_ingress)
firewall = self._fake_firewall_group(rule_list, is_ingress=is_ingress)
with mock.patch.object(self.plugin.fwaas_callbacks, 'get_port_fwg',
return_value=firewall),\
mock.patch.object(self.plugin.fwaas_callbacks,
'_get_port_firewall_group_id',
return_value=FAKE_FW_ID),\
mock.patch.object(self.plugin.fwaas_callbacks,
'_get_fw_group_from_plugin',
return_value=firewall),\
mock.patch("vmware_nsx.db.nsxv_db.get_edge_vnic_binding",
return_value=FAKE_DB_OBJ),\
mock.patch.object(edge_utils, "update_firewall") as update_fw,\
mock.patch.object(edge_utils, 'get_router_edge_id',
return_value='edge-1'):
func('nsx', apply_list, firewall)
expected_rules = self._fake_translated_rules(
rule_list,
'vnic-index-1', is_ingress=is_ingress) + [
{'name': "Block port ingress",
'action': edge_firewall_driver.FWAAS_DENY,
'destination_vnic_groups': ['vnic-index-1'],
'logged': False},
{'name': "Block port egress",
'action': edge_firewall_driver.FWAAS_DENY,
'source_vnic_groups': ['vnic-index-1'],
'logged': False}]
update_fw.assert_called_once_with(
self.plugin.nsx_v, mock.ANY, FAKE_ROUTER_ID,
{'firewall_rule_list': expected_rules})
def test_create_firewall_with_ingress_rules(self):
self._setup_firewall_with_rules(self.firewall.create_firewall_group)
def test_update_firewall_with_ingress_rules(self):
self._setup_firewall_with_rules(self.firewall.update_firewall_group)
def test_create_firewall_with_egress_rules(self):
self._setup_firewall_with_rules(self.firewall.create_firewall_group,
is_ingress=False)
def test_update_firewall_with_egress_rules(self):
self._setup_firewall_with_rules(self.firewall.update_firewall_group,
is_ingress=False)
def test_create_firewall_with_illegal_rules(self):
"""Use ingress rules as the egress list and verify failure"""
apply_list = self._fake_apply_list()
rule_list = self._fake_rules_v4(is_ingress=True)
firewall = self._fake_firewall_group(rule_list, is_ingress=False)
self.assertRaises(exceptions.FirewallInternalDriverError,
self.firewall.create_firewall_group, 'nsx',
apply_list, firewall)
def test_delete_firewall(self):
apply_list = self._fake_apply_list()
firewall = self._fake_empty_firewall_group()
with mock.patch.object(self.plugin.fwaas_callbacks, 'get_port_fwg',
return_value=None),\
mock.patch("vmware_nsx.db.db.get_nsx_switch_and_port_id",
return_value=('vnic-index-1', 0)),\
mock.patch.object(edge_utils, "update_firewall") as update_fw,\
mock.patch.object(edge_utils, 'get_router_edge_id',
return_value='edge-1'):
self.firewall.delete_firewall_group('nsx', apply_list, firewall)
update_fw.assert_called_once_with(
self.plugin.nsx_v, mock.ANY, FAKE_ROUTER_ID,
{'firewall_rule_list': []})
def test_create_firewall_with_admin_down(self):
apply_list = self._fake_apply_list()
rule_list = self._fake_rules_v4()
firewall = self._fake_firewall_group_with_admin_down(rule_list)
with mock.patch.object(edge_utils, "update_firewall") as update_fw,\
mock.patch.object(edge_utils, 'get_router_edge_id',
return_value='edge-1'):
self.firewall.create_firewall_group('nsx', apply_list, firewall)
update_fw.assert_called_once_with(
self.plugin.nsx_v, mock.ANY, FAKE_ROUTER_ID,
{'firewall_rule_list': []})