FWaaS v2 utilize L3 Agent Extension framework

This updates the FWaaS v2 L3 code to move away from an inheritance-based
model and use the new L3 agent extension framework.

This change rolls back [1] which is the inheritance-based model.

[1] https://review.openstack.org/315826

Partial-Implements: blueprint fwaas-api-2.0
Co-Authored-By: Nate Johnston <nate_johnston@cable.comcast.com>
Co-Authored-By: Chandan Dutta Chowdhury <chandanc@juniper.net>
Depends-On: I85f89accbeefd820130335674fd56cb54f1449de

Change-Id: Ib29b96e73d09530cbf627a98180fb1a591e42e3f
This commit is contained in:
Margaret Frances 2016-08-15 13:26:30 -04:00 committed by Nate Johnston
parent b09e41243d
commit 6718fd8560
18 changed files with 301 additions and 206 deletions

View File

@ -35,6 +35,7 @@ function install_fwaas() {
function configure_fwaas() {
neutron_fwaas_configure_driver
iniset_multiline $Q_L3_CONF_FILE AGENT extensions fwaas
}
function init_fwaas() {

View File

@ -1,62 +0,0 @@
# 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 sys
from oslo_config import cfg
from oslo_service import service
from neutron.agent.common import config
from neutron.agent.l3 import ha
from neutron.agent.linux import external_process
from neutron.agent.linux import interface
from neutron.agent.linux import pd
from neutron.agent.linux import ra
from neutron.agent.metadata import config as metadata_config
from neutron.common import config as common_config
from neutron.common import topics
from neutron.conf.agent.l3 import config as l3_config
from neutron import service as neutron_service
from neutron_fwaas.services.firewall.agents import firewall_agent_api as fwa
FWAAS_AGENTS = {fwa.FWAAS_V1: ('neutron_fwaas.services.firewall.agents.'
'l3reference.firewall_l3_agent.L3WithFWaaS'),
fwa.FWAAS_V2: ('neutron_fwaas.services.firewall.agents.'
'l3reference.firewall_l3_agent_v2.L3WithFWaaS')}
def register_opts(conf):
conf.register_opts(l3_config.OPTS)
conf.register_opts(metadata_config.DRIVER_OPTS)
conf.register_opts(metadata_config.SHARED_OPTS)
conf.register_opts(ha.OPTS)
config.register_interface_driver_opts_helper(conf)
config.register_agent_state_opts_helper(conf)
conf.register_opts(interface.OPTS)
conf.register_opts(external_process.OPTS)
conf.register_opts(pd.OPTS)
conf.register_opts(ra.OPTS)
config.register_availability_zone_opts_helper(conf)
def main():
register_opts(cfg.CONF)
common_config.init(sys.argv[1:])
config.setup_logging()
manager = FWAAS_AGENTS[cfg.CONF.fwaas.agent_version]
server = neutron_service.Service.create(
binary='neutron-l3-agent',
topic=topics.L3_AGENT,
report_interval=cfg.CONF.AGENT.report_interval,
manager=manager)
service.launch(cfg.CONF, server).wait()

View File

@ -16,4 +16,5 @@
# Constants for "topics"
FIREWALL_PLUGIN = 'q-firewall-plugin'
L3_AGENT = 'l3_agent'
FW_AGENT = 'firewall_agent'
FIREWALL_RULE_LIST = 'firewall_rule_list'

View File

@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron.common import eventlet_utils
from neutron_fwaas.db.firewall.v2 import firewall_db_v2
eventlet_utils.monkey_patch()
FIREWALL_GROUP = firewall_db_v2.FirewallGroup
FIREWALL_POLICY = firewall_db_v2.FirewallPolicy
FIREWALL_RULE = firewall_db_v2.FirewallRuleV2

View File

@ -46,6 +46,10 @@ class FirewallGroupInPendingState(nexception.Conflict):
"%(firewall_id)s is in %(pending_state)s.")
class FirewallGroupPortInvalid(nexception.Conflict):
message = _("Firewall Group Port %(port_id)s is invalid")
class FirewallGroupPortInvalidProject(nexception.Conflict):
message = _("Firewall Group %(port_id)s in invalid Project")

View File

@ -13,8 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron.agent.l3 import agent
from neutron.agent.linux import ip_lib
from neutron.agent.l3 import l3_agent_extension
from neutron.common import rpc as n_rpc
from neutron import context
from neutron.plugins.common import constants as n_const
from oslo_config import cfg
@ -23,12 +23,16 @@ from oslo_log import log as logging
from neutron_fwaas._i18n import _, _LE
from neutron_fwaas.common import fwaas_constants as f_const
from neutron_fwaas.common import resources as f_resources
from neutron_fwaas.extensions import firewall as fw_ext
from neutron_fwaas.services.firewall.agents import firewall_agent_api as api
from neutron_fwaas.services.firewall.agents import firewall_service
LOG = logging.getLogger(__name__)
#TODO(njohnston): There needs to be some extrapolation of the common code
# between this module and firewall_l3_agent_v2.py.
class FWaaSL3PluginApi(api.FWaaSPluginApiMixin):
"""Agent side of the FWaaS agent to FWaaS Plugin RPC API."""
@ -49,14 +53,39 @@ class FWaaSL3PluginApi(api.FWaaSPluginApiMixin):
'get_tenants_with_firewalls', host=self.host)
class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
class FWaaSL3AgentExtension(l3_agent_extension.L3AgentCoreResourceExtension):
"""FWaaS Agent support to be used by Neutron L3 agent."""
SUPPORTED_RESOURCE_TYPES = [f_resources.FIREWALL_GROUP,
f_resources.FIREWALL_POLICY,
f_resources.FIREWALL_RULE]
def initialize(self, connection, driver_type):
self._register_rpc_consumers(connection)
def consume_api(self, agent_api):
LOG.debug("FWaaS consume_api call occurred with %s" % agent_api)
self.agent_api = agent_api
def _register_rpc_consumers(self, connection):
#TODO(njohnston): Add RPC consumer connection loading here.
pass
def start_rpc_listeners(self, conf):
self.endpoints = [self]
self.conn = n_rpc.create_connection()
self.conn.create_consumer(
f_const.FW_AGENT, self.endpoints, fanout=False)
return self.conn.consume_in_threads()
def __init__(self, host, conf):
LOG.debug("Initializing firewall agent")
self.agent_api = None
self.neutron_service_plugins = None
self.conf = conf
self.fwaas_enabled = cfg.CONF.fwaas.enabled
self.start_rpc_listeners(conf)
# None means l3-agent has no information on the server
# configuration due to the lack of RPC support.
@ -77,8 +106,7 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
self.services_sync_needed = False
# setup RPC to msg fwaas plugin
self.fwplugin_rpc = FWaaSL3PluginApi(f_const.FIREWALL_PLUGIN,
conf.host)
super(FWaaSL3AgentRpcCallback, self).__init__(host=conf.host)
host)
def _has_router_insertion_fields(self, fw):
return 'add-router-ids' in fw
@ -90,36 +118,24 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
return (fw['del-router-ids'] if to_delete
else fw['add-router-ids'])
else:
# we are in a upgrade and msg from older version of plugin
try:
routers = self.plugin_rpc.get_routers(context)
except Exception:
LOG.exception(
_LE("FWaaS RPC failure in _get_router_ids_for_fw "
"for firewall: %(fwid)s"),
{'fwid': fw['id']})
self.services_sync_needed = True
return [
router['id']
for router in routers
if router['tenant_id'] == fw['tenant_id']]
return [router['id'] for router in
self.agent_api.get_routers_in_project(fw['tenant_id'])]
def _get_routers_in_project(self, project_id):
if self.agent_api is None:
LOG.exception(_LE("FWaaS RPC call failed; L3 agent_api failure"))
router_info = self.agent_api._router_info
if project_id:
return [ri for ri in router_info.values()
if ri.router['tenant_id'] == project_id]
else:
return []
def _get_router_info_list_for_tenant(self, router_ids, tenant_id):
"""Returns the list of router info objects on which to apply the fw."""
root_ip = ip_lib.IPWrapper()
local_ns_list = root_ip.get_namespaces()
router_info_list = []
# Pick up namespaces for Tenant Routers
for rid in router_ids:
# for routers without an interface - get_routers returns
# the router - but this is not yet populated in router_info
if rid not in self.router_info:
continue
router_ns = self.router_info[rid].ns_name
if router_ns in local_ns_list:
router_info_list.append(self.router_info[rid])
return router_info_list
return [ri for ri in self._get_routers_in_project(tenant_id)
if ri.router_id in router_ids and
self.agent_api.is_router_in_namespace(ri.router_id)]
def _invoke_driver_for_sync_from_plugin(self, ctx, router_info_list, fw):
"""Invoke the delete driver method for status of PENDING_DELETE and
@ -165,17 +181,17 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
fw['id'],
status)
def _process_router_add(self, ri):
def _process_router_add(self, router):
"""On router add, get fw with rules from plugin and update driver."""
LOG.debug("Process router add, router_id: '%s'", ri.router['id'])
router_ids = ri.router['id']
LOG.debug("Process router add, router_id: '%s'", router['id'])
router_ids = router['id']
router_info_list = self._get_router_info_list_for_tenant(
[router_ids],
ri.router['tenant_id'])
router['tenant_id'])
if router_info_list:
# Get the firewall with rules
# for the tenant the router is on.
ctx = context.Context('', ri.router['tenant_id'])
ctx = context.Context('', router['tenant_id'])
fw_list = self.fwplugin_rpc.get_firewalls_for_tenant(ctx)
for fw in fw_list:
if self._has_router_insertion_fields(fw):
@ -190,7 +206,7 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
# router can be present only on one fw
return
def process_router_add(self, ri):
def add_router(self, context, new_router):
"""On router add, get fw with rules from plugin and update driver.
Handles agent restart, when a router is added, query the plugin to
@ -201,15 +217,26 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
if not self.fwaas_enabled:
return
try:
# TODO(sridar): as per discussion with pc_m, we may want to hook
# this up to the l3 agent observer notification
self._process_router_add(ri)
self._process_router_add(new_router)
except Exception:
LOG.exception(
_LE("FWaaS RPC info call failed for '%s'."),
ri.router['id'])
new_router['id'])
self.services_sync_needed = True
def update_router(self, context, updated_router):
"""The update_router method is just a synonym for add_router"""
self.add_router(context, updated_router)
def delete_router(self, context, new_router):
"""Handles router deletion. There is basically nothing to do for this
in the context of FWaaS with an IPTables driver; the namespace will
already have been deleted, taking the IPTables rules with it.
"""
#TODO(njohnston): When another firewall driver is implemented, look at
# expanding this out so that the driver can handle deletion calls.
pass
def process_services_sync(self, ctx):
if not self.services_sync_needed:
return
@ -403,9 +430,9 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
self.services_sync_needed = True
class L3WithFWaaS(FWaaSL3AgentRpcCallback, agent.L3NATAgentWithStateReport):
class L3WithFWaaS(FWaaSL3AgentExtension):
def __init__(self, host, conf=None):
def __init__(self, conf=None):
if conf:
self.conf = conf
else:

View File

@ -13,8 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron.agent.l3 import agent
from neutron.agent.l3 import l3_agent_extension
from neutron.agent.linux import ip_lib
from neutron.common import rpc as n_rpc
from neutron import context
from neutron.plugins.common import constants as n_const
from neutron_fwaas.common import fwaas_constants as f_const
@ -23,6 +24,7 @@ from oslo_log import helpers as log_helpers
from oslo_log import log as logging
from neutron_fwaas._i18n import _, _LE
from neutron_fwaas.common import resources as f_resources
from neutron_fwaas.extensions import firewall as fw_ext
from neutron_fwaas.services.firewall.agents import firewall_agent_api as api
from neutron_fwaas.services.firewall.agents import firewall_service
@ -67,15 +69,40 @@ class FWaaSL3PluginApi(api.FWaaSPluginApiMixin):
fwg_id=fwg_id, status=status, host=self.host)
class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
"""FWaaS agent support to be used by neutron's L3 agent."""
class FWaaSL3AgentExtension(l3_agent_extension.L3AgentCoreResourceExtension):
"""FWaaS agent extension."""
SUPPORTED_RESOURCE_TYPES = [f_resources.FIREWALL_GROUP,
f_resources.FIREWALL_POLICY,
f_resources.FIREWALL_RULE]
def initialize(self, connection, driver_type):
self._register_rpc_consumers(connection)
def consume_api(self, agent_api):
LOG.debug("FWaaS consume_api call occurred with %s" % agent_api)
self.agent_api = agent_api
def _register_rpc_consumers(self, connection):
#TODO(njohnston): Add RPC consumer connection loading here.
pass
def start_rpc_listeners(self, host, conf):
self.endpoints = [self]
self.conn = n_rpc.create_connection()
self.conn.create_consumer(
f_const.FW_AGENT, self.endpoints, fanout=False)
return self.conn.consume_in_threads()
def __init__(self, host, conf):
LOG.debug("Initializing firewall group agent")
self.agent_api = None
self.neutron_service_plugins = None
self.conf = conf
self.fwaas_enabled = cfg.CONF.fwaas.enabled
self.start_rpc_listeners(host, conf)
# None means l3-agent has no information on the server
# configuration due to the lack of RPC support.
if self.neutron_service_plugins is not None:
@ -96,7 +123,7 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
self.services_sync_needed = False
self.fwplugin_rpc = FWaaSL3PluginApi(f_const.FIREWALL_PLUGIN,
host)
super(FWaaSL3AgentRpcCallback, self).__init__(host=host)
super(FWaaSL3AgentExtension, self).__init__()
@property
def _local_namespaces(self):
@ -127,7 +154,8 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
else:
fwg_port_ids = firewall_group['add-port-ids']
elif not require_new_plugin:
routers = [self.router_info[rid] for rid in self.router_info]
routers = self.agent_api.get_routers_in_project(
firewall_group['tenant_id'])
for router in routers:
if router.router['tenant_id'] == firewall_group['tenant_id']:
fwg_port_ids.extend([p['id'] for p in
@ -140,21 +168,17 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
"""Returns port objects in the local namespace, along with their
router_info.
"""
in_ns_ports = []
if port_ids:
for router_id in self.router_info:
# For routers without an interface - get_routers returns
# the router - but this is not yet populated in router_info
router_info = self.router_info[router_id]
if router_info.ns_name not in self._local_namespaces:
continue
in_ns_router_port_ids = []
for port in router_info.internal_ports:
if port['id'] in port_ids:
in_ns_router_port_ids.append(port['id'])
if in_ns_router_port_ids:
in_ns_ports.append((router_info, in_ns_router_port_ids))
return in_ns_ports
in_ns_ports = {} # This will be converted to a list later.
if port_ids and self.agent_api:
for port_id in port_ids:
# This fetched router_info is guaranteed to be in_namespace.
router_info = self.agent_api.get_router_hosting_port(port_id)
if router_info:
if router_info in in_ns_ports:
in_ns_ports[router_info].append(port_id)
else:
in_ns_ports[router_info] = [port_id]
return list(in_ns_ports.items())
def _invoke_driver_for_sync_from_plugin(self, ctx, port, firewall_group):
"""Calls the FWaaS driver's delete_firewall_group method if firewall
@ -200,29 +224,27 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
self.fwplugin_rpc.set_firewall_group_status(
ctx, firewall_group['id'], status)
def _process_router_add(self, new_router):
"""If the new router is in the local namespace, queries the plugin to
get the firewall groups for the project in question and then sees if
the router has any ports for any firewall group that is configured
for that project. If so, installs firewall group rules on the
requested ports on this router.
def _process_router_update(self, updated_router):
"""If a new or existing router in the local namespace is updated,
queries the plugin to get the firewall groups for the project in
question and then sees if the router has any ports for any firewall
group that is configured for that project. If so, installs firewall
group rules on the requested ports on this router.
"""
LOG.debug("Process router add, router_id: %s.",
new_router.router['id'])
router_id = new_router.router['id']
if router_id not in self.router_info or \
self.router_info[router_id].ns_name not in \
self._local_namespaces:
LOG.debug("Process router update, router_id: %s tenant: %s.",
updated_router['id'], updated_router['tenant_id'])
router_id = updated_router['id']
if not self.agent_api.is_router_in_namespace(router_id):
return
# Get the firewall groups for the new router's project.
# NOTE: Vernacular move from "tenant" to "project" doesn't yet appear
# as a key in router or firewall group objects.
ctx = context.Context('', new_router.router['tenant_id'])
ctx = context.Context('', updated_router['tenant_id'])
fwg_list = self.fwplugin_rpc.get_firewall_groups_for_project(ctx)
# Apply a firewall group, as requested, to ports on the new router.
for port in new_router.router.internal_ports:
for port in updated_router['_interfaces']:
for firewall_group in fwg_list:
if (self._has_port_insertion_fields(firewall_group) and
(port['id'] in firewall_group['add-port-ids'] or
@ -232,7 +254,7 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
# A port can have at most one firewall group.
break
def process_router_add(self, new_router):
def add_router(self, context, new_router):
"""Handles agent restart and router add. Fetches firewall groups from
plugin and updates driver.
"""
@ -240,12 +262,37 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
return
try:
self._process_router_add(new_router)
self._process_router_update(new_router)
except Exception:
LOG.exception(_LE("FWaaS RPC info call failed for %s"),
new_router.router['id'])
LOG.exception(_LE("FWaaS router add RPC info call failed for %s"),
new_router['id'])
self.services_sync_needed = True
def update_router(self, context, updated_router):
"""Handles agent restart and router add. Fetches firewall groups from
plugin and updates driver.
"""
if not self.fwaas_enabled:
return
try:
self._process_router_update(updated_router)
except Exception:
#TODO(njohnston): This repr should be replaced.
LOG.exception(
_LE("FWaaS router update RPC info call failed for %s"),
repr(updated_router))
self.services_sync_needed = True
def delete_router(self, context, new_router):
"""Handles router deletion. There is basically nothing to do for this
in the context of FWaaS with an IPTables driver; the namespace will
already have been deleted, taking the IPTables rules with it.
"""
#TODO(njohnston): When another firewall driver is implemented, look at
# expanding this out so that the driver can handle deletion calls.
pass
def process_services_sync(self, ctx):
"""Syncs with plugin and applies the sync data.
"""
@ -283,7 +330,6 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
# Get the in-namespace ports to which to add the firewall group.
ports_for_fwg = self._get_firewall_group_ports(context, firewall_group)
if not ports_for_fwg:
return
@ -451,9 +497,9 @@ class FWaaSL3AgentRpcCallback(api.FWaaSAgentRpcCallbackMixin):
self.services_sync_needed = True
class L3WithFWaaS(FWaaSL3AgentRpcCallback, agent.L3NATAgentWithStateReport):
class L3WithFWaaS(FWaaSL3AgentExtension):
def __init__(self, host, conf=None):
def __init__(self, conf=None):
if conf:
self.conf = conf
else:

View File

@ -59,8 +59,8 @@ class FwaasDriverBase(object):
application of rules. Argument agent_mode indicates the l3 agent in DVR or
DVR_SNAT or LEGACY mode.
"""
@abc.abstractmethod
# TODO(Margaret): Remove the first 3 methods and make the second three
# @abc.abstractmethod
def create_firewall(self, agent_mode, apply_list, firewall):
"""Create the Firewall with default (drop all) policy.
@ -69,7 +69,6 @@ class FwaasDriverBase(object):
"""
pass
@abc.abstractmethod
def delete_firewall(self, agent_mode, apply_list, firewall):
"""Delete firewall.
@ -78,7 +77,6 @@ class FwaasDriverBase(object):
"""
pass
@abc.abstractmethod
def update_firewall(self, agent_mode, apply_list, firewall):
"""Apply the policy on all trusted interfaces.
@ -87,6 +85,30 @@ class FwaasDriverBase(object):
"""
pass
def create_firewall_group(self, agent_mode, apply_list, firewall):
"""Create the Firewall with default (drop all) policy.
The default policy will be applied on all the interfaces of
trusted zone.
"""
pass
def delete_firewall_group(self, agent_mode, apply_list, firewall):
"""Delete firewall.
Removes all policies created by this instance and frees up
all the resources.
"""
pass
def update_firewall_group(self, agent_mode, apply_list, firewall):
"""Apply the policy on all trusted interfaces.
Remove previous policy and apply the new policy on all trusted
interfaces.
"""
pass
@abc.abstractmethod
def apply_default_policy(self, agent_mode, apply_list, firewall):
"""Apply the default policy on all trusted interfaces.

View File

@ -58,6 +58,9 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
LOG.debug("Initializing fwaas iptables driver")
self.pre_firewall = None
def initialize(self):
pass
def _get_intf_name(self, if_prefix, port_id):
_name = "%s%s" % (if_prefix, port_id)
return _name[:MAX_INTF_NAME_LEN]
@ -78,7 +81,7 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
LOG.exception(_LE("Failed to create firewall: %s"), firewall['id'])
raise fw_ext.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
def _get_ipt_mgrs_with_if_prefix(self, agent_mode, router_info):
def _get_ipt_mgrs_with_if_prefix(self, agent_mode, ri):
"""Gets the iptables manager along with the if prefix to apply rules.
With DVR we can have differing namespaces depending on which agent
@ -88,18 +91,18 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
namespace and a fip so this is provided back as a list - so in that
scenario rules can be applied on both.
"""
if not router_info.router.get('distributed'):
return [{'ipt': router_info.iptables_manager,
if not ri.router.get('distributed'):
return [{'ipt': ri.iptables_manager,
'if_prefix': INTERNAL_DEV_PREFIX}]
ipt_mgrs = []
# TODO(sridar): refactor to get strings to a common location.
if agent_mode == 'dvr_snat':
if router_info.snat_iptables_manager:
ipt_mgrs.append({'ipt': router_info.snat_iptables_manager,
if ri.snat_iptables_manager:
ipt_mgrs.append({'ipt': ri.snat_iptables_manager,
'if_prefix': SNAT_INT_DEV_PREFIX})
if router_info.dist_fip_count:
if ri.dist_fip_count:
# handle the fip case on n/w or compute node.
ipt_mgrs.append({'ipt': router_info.iptables_manager,
ipt_mgrs.append({'ipt': ri.iptables_manager,
'if_prefix': ROUTER_2_FIP_DEV_PREFIX})
return ipt_mgrs
@ -108,9 +111,9 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
{'fw_id': firewall['id'], 'tid': firewall['tenant_id']})
fwid = firewall['id']
try:
for router_info, router_fw_ports in apply_list:
for ri, router_fw_ports in apply_list:
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
agent_mode, router_info)
agent_mode, ri)
for ipt_if_prefix in ipt_if_prefix_list:
ipt_mgr = ipt_if_prefix['ipt']
self._remove_chains(fwid, ipt_mgr)
@ -148,9 +151,9 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
{'fw_id': firewall['id'], 'tid': firewall['tenant_id']})
fwid = firewall['id']
try:
for router_info, router_fw_ports in apply_list:
for ri, router_fw_ports in apply_list:
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
agent_mode, router_info)
agent_mode, ri)
for ipt_if_prefix in ipt_if_prefix_list:
# the following only updates local memory; no hole in FW
ipt_mgr = ipt_if_prefix['ipt']
@ -172,9 +175,9 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
def _setup_firewall(self, agent_mode, apply_list, firewall):
fwid = firewall['id']
for router_info, router_fw_ports in apply_list:
for ri, router_fw_ports in apply_list:
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
agent_mode, router_info)
agent_mode, ri)
for ipt_if_prefix in ipt_if_prefix_list:
ipt_mgr = ipt_if_prefix['ipt']
# the following only updates local memory; no hole in FW
@ -298,9 +301,9 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
def _remove_conntrack_new_firewall(self, agent_mode, apply_list, firewall):
"""Remove conntrack when create new firewall"""
routers_list = list(set([apply_info[0] for apply_info in apply_list]))
for router_info in routers_list:
for ri in routers_list:
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
agent_mode, router_info)
agent_mode, ri)
for ipt_if_prefix in ipt_if_prefix_list:
ipt_mgr = ipt_if_prefix['ipt']
cmd = self._get_conntrack_cmd_from_rule(ipt_mgr)
@ -310,9 +313,9 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
apply_list, pre_firewall, firewall):
"""Remove conntrack when updated firewall"""
routers_list = list(set([apply_info[0] for apply_info in apply_list]))
for router_info in routers_list:
for ri in routers_list:
ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix(
agent_mode, router_info)
agent_mode, ri)
for ipt_if_prefix in ipt_if_prefix_list:
ipt_mgr = ipt_if_prefix['ipt']
ch_rules = self._find_changed_rules(pre_firewall,
@ -391,7 +394,7 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
jump_rule = ['%s %s -j %s-%s' % (
IPTABLES_DIR[direction], intf_name,
bname, chain_name)]
self._add_rules_to_chain(ipt_mgr, ver,
self._add_rules_to_chain(ipt_mgr, ver,
'FORWARD', jump_rule)
# jump to DROP_ALL policy

View File

@ -148,7 +148,7 @@ class FirewallPlugin(
self.start_rpc_listeners()
self.agent_rpc = FirewallAgentApi(
f_const.L3_AGENT,
f_const.FW_AGENT,
cfg.CONF.host
)
firewall_db.subscribe()

View File

@ -107,11 +107,11 @@ class FirewallCallbacks(object):
if fwg['status'] == n_const.PENDING_DELETE:
fwg_with_rules['add-port-ids'] = []
fwg_with_rules['del-port-ids'] = (
self.plugin._get_ports_for_firewall_group(context,
self.plugin._get_ports_in_firewall_group(context,
fwg['id']))
else:
fwg_with_rules['add-port-ids'] = (
self.plugin._get_ports_for_firewall_group(context,
self.plugin._get_ports_in_firewall_group(context,
fwg['id']))
fwg_with_rules['del-port-ids'] = []
fwg_list.append(fwg_with_rules)
@ -142,7 +142,7 @@ class FirewallPluginV2(
self.start_rpc_listeners()
self.agent_rpc = FirewallAgentApi(
f_const.L3_AGENT,
f_const.FW_AGENT,
cfg.CONF.host
)
@ -205,6 +205,8 @@ class FirewallPluginV2(
# TODO(sridar): elevated context and do we want to use public ?
for port_id in fwg_ports:
port_db = self._core_plugin._get_port(context, port_id)
if port_db['device_owner'] != "network:router_interface":
raise fw_ext.FirewallGroupPortInvalid(port_id=port_id)
if port_db['tenant_id'] != tenant_id:
raise fw_ext.FirewallGroupPortInvalidProject(port_id=port_id)
return

View File

@ -12,13 +12,15 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import testtools
import uuid
import mock
from oslo_config import cfg
from neutron.agent.l3 import config as l3_config
from neutron.agent.l3 import ha
from neutron.agent.l3 import l3_agent_extension_api as l3_agent_api
from neutron.agent.l3 import router_info
from neutron.agent.linux import ip_lib
from neutron.conf import common as base_config
@ -38,12 +40,12 @@ class FWaasHelper(object):
pass
class FWaasAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback, FWaasHelper):
class FWaasAgent(firewall_l3_agent.FWaaSL3AgentExtension, FWaasHelper):
neutron_service_plugins = []
def _setup_test_agent_class(service_plugins):
class FWaasTestAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
class FWaasTestAgent(firewall_l3_agent.FWaaSL3AgentExtension,
FWaasHelper):
neutron_service_plugins = service_plugins
@ -64,13 +66,15 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
self.conf.register_opts(l3_config.OPTS)
self.conf.register_opts(ha.OPTS)
self.conf.register_opts(firewall_agent_api.FWaaSOpts, 'fwaas')
self.api = FWaasAgent("myhost", self.conf)
self.api = FWaasAgent(host=None, conf=self.conf)
self.api.fwaas_driver = test_firewall_agent_api.NoopFwaasDriver()
self.adminContext = context.get_admin_context()
self.router_id = str(uuid.uuid4())
self.agent_conf = mock.Mock()
project_id = str(uuid.uuid4()) # For 'tenant_id' and 'project_id' keys
self.ri_kwargs = {'router': {'id': self.router_id,
'tenant_id': str(uuid.uuid4())},
'tenant_id': project_id,
'project_id': project_id},
'agent_conf': self.agent_conf,
'interface_driver': mock.ANY,
'use_ipv6': mock.ANY,
@ -82,8 +86,8 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
with mock.patch('oslo_utils.importutils.import_object'):
test_agent_class(cfg.CONF)
@testtools.skip('needs to be refactored for fwaas v2')
def test_fw_config_mismatch_plugin_enabled_agent_disabled(self):
self.skipTest('this is broken')
test_agent_class = _setup_test_agent_class([constants.FIREWALL])
cfg.CONF.set_override('enabled', False, 'fwaas')
self.assertRaises(SystemExit, test_agent_class, cfg.CONF)
@ -300,9 +304,15 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
def test_get_router_info_list_for_tenant(self):
ri = self._prepare_router_data()
router_info = {ri.router_id: ri}
self.api.router_info = router_info
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
self.api.consume_api(api_object)
routers = [ri.router]
router_ids = [router['id'] for router in routers]
self.api.router_info = {ri.router_id: ri}
with mock.patch.object(ip_lib.IPWrapper,
'get_namespaces') as mock_get_namespaces:
mock_get_namespaces.return_value = []
@ -316,19 +326,27 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
rtr_with_ri):
# ri.router with associated router_info (ri)
# rtr2 has no router_info
ri = self._prepare_router_data()
rtr2 = {'id': str(uuid.uuid4()), 'tenant_id': ri.router['tenant_id']}
routers = [rtr2]
self.api.router_info = {}
router_info = {}
ri_expected = []
if rtr_with_ri:
self.api.router_info[ri.router_id] = ri
router_info[ri.router_id] = ri
routers.append(ri.router)
ri_expected.append(ri)
self.api.router_info = router_info
router_ids = [router['id'] for router in routers]
with mock.patch.object(ip_lib.IPWrapper,
'get_namespaces') as mock_get_namespaces:
mock_get_namespaces.return_value = ri.ns_name
mock_get_namespaces.return_value = [ri.ns_name]
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
self.api.consume_api(api_object)
router_info_list = self.api._get_router_info_list_for_tenant(
router_ids,
ri.router['tenant_id'])

View File

@ -19,6 +19,7 @@ import mock
from oslo_config import cfg
from neutron.agent.l3 import config as l3_config
from neutron.agent.l3 import l3_agent_extension_api as l3_agent_api
from neutron.agent.l3 import router_info
from neutron.agent.linux import ip_lib
from neutron import context
@ -33,35 +34,54 @@ from neutron_fwaas.tests.unit.services.firewall.agents \
class FWaasHelper(object):
def __init__(self, host):
def __init__(self):
pass
class FWaasAgent(firewall_l3_agent_v2.FWaaSL3AgentRpcCallback, FWaasHelper):
class FWaasAgent(firewall_l3_agent_v2.L3WithFWaaS, FWaasHelper):
neutron_service_plugins = []
def add_router(self, context, data):
pass
def delete_router(self, context, data):
pass
def update_router(self, context, data):
pass
def _setup_test_agent_class(service_plugins):
class FWaasTestAgent(firewall_l3_agent_v2.FWaaSL3AgentRpcCallback,
class FWaasTestAgent(firewall_l3_agent_v2.L3WithFWaaS,
FWaasHelper):
neutron_service_plugins = service_plugins
def __init__(self, conf):
self.event_observers = mock.Mock()
self.conf = conf
super(FWaasTestAgent, self).__init__('myhost', conf)
super(FWaasTestAgent, self).__init__(conf)
def add_router(self, context, data):
pass
def delete_router(self, context, data):
pass
def update_router(self, context, data):
pass
return FWaasTestAgent
class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
class TestFWaaSL3AgentExtension(base.BaseTestCase):
def setUp(self):
super(TestFwaasL3AgentRpcCallback, self).setUp()
super(TestFWaaSL3AgentExtension, self).setUp()
self.conf = cfg.ConfigOpts()
self.conf.register_opts(l3_config.OPTS)
self.conf.register_opts(firewall_agent_api.FWaaSOpts, 'fwaas')
self.api = FWaasAgent('myhost', self.conf)
self.conf.host = 'myhost'
self.api = FWaasAgent(self.conf)
self.api.fwaas_driver = test_firewall_agent_api.NoopFwaasDriverV2()
self.adminContext = context.get_admin_context()
self.context = mock.sentinel.context
@ -279,7 +299,9 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
ports = [{'id': pid} for pid in port_ids]
ri = self._prepare_router_data()
ri.internal_ports = ports
self.api.router_info = {ri.router_id: ri}
router_info = {ri.router_id: ri}
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
self.api.consume_api(api_object)
fw_port_ids = port_ids
with mock.patch.object(ip_lib.IPWrapper,
@ -288,7 +310,7 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
mock_get_namespaces.return_value = []
ports_for_fw_list = self.api._get_in_ns_ports(fw_port_ids)
mock_get_namespaces.assert_called_once_with()
mock_get_namespaces.assert_called_with()
self.assertFalse(ports_for_fw_list)
def test_get_in_ns_ports_for_fw(self):
@ -296,8 +318,10 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
ports = [{'id': pid} for pid in port_ids]
ri = self._prepare_router_data()
ri.internal_ports = ports
self.api.router_info = {}
self.api.router_info[ri.router_id] = ri
router_info = {}
router_info[ri.router_id] = ri
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
self.api.consume_api(api_object)
fw_port_ids = port_ids
ports_for_fw_expected = [(ri, port_ids)]
@ -306,3 +330,5 @@ class TestFwaasL3AgentRpcCallback(base.BaseTestCase):
mock_get_namespaces.return_value = [ri.ns_name]
ports_for_fw_actual = self.api._get_in_ns_ports(fw_port_ids)
self.assertEqual(ports_for_fw_expected, ports_for_fw_actual)
#TODO(Margaret) Add test for add_router method.

View File

@ -28,13 +28,13 @@ class NoopFwaasDriver(fwaas_base.FwaasDriverBase):
This driver is for disabling Fwaas functionality.
"""
def create_firewall(self, agent_mode, apply_list, firewall):
def create_firewall_group(self, agent_mode, apply_list, firewall):
pass
def delete_firewall(self, agent_mode, apply_list, firewall):
def delete_firewall_group(self, agent_mode, apply_list, firewall):
pass
def update_firewall(self, agent_mode, apply_list, firewall):
def update_firewall_group(self, agent_mode, apply_list, firewall):
pass
def apply_default_policy(self, agent_mode, apply_list, firewall):

View File

@ -181,11 +181,14 @@ class IptablesFwaasTestCase(base.BaseTestCase):
mock.call.add_rule(egress_chain, rule2),
mock.call.add_rule(egress_chain, rule3)]
intf_name = self._get_intf_name(if_prefix, FAKE_PORT_IDS[-1])
calls.append(mock.call.add_rule('FORWARD',
'-o %s -j %s' % (intf_name, ipt_mgr_ichain)))
calls.append(mock.call.add_rule('FORWARD',
'-i %s -j %s' % (intf_name, ipt_mgr_echain)))
for port in FAKE_PORT_IDS:
intf_name = self._get_intf_name(if_prefix, port)
calls.append(mock.call.add_rule('FORWARD',
'-o %s -j %s' % (intf_name, ipt_mgr_ichain)))
for port in FAKE_PORT_IDS:
intf_name = self._get_intf_name(if_prefix, port)
calls.append(mock.call.add_rule('FORWARD',
'-i %s -j %s' % (intf_name, ipt_mgr_echain)))
for direction in ['o', 'i']:
for port_id in FAKE_PORT_IDS:

View File

@ -27,13 +27,12 @@ setup-hooks =
pbr.hooks.setup_hook
[entry_points]
console_scripts =
neutron-l3-agent = neutron_fwaas.cmd.eventlet.agents.fw:main
firewall_drivers =
# These are for backwards compat with Juno firewall service provider
# configuration values
neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas:IptablesFwaasDriver
iptables = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas:IptablesFwaasDriver
iptables_v2 = neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas_v2:IptablesFwaasDriver
neutron.service_plugins =
firewall = neutron_fwaas.services.firewall.fwaas_plugin:FirewallPlugin
firewall_v2 = neutron_fwaas.services.firewall.fwaas_plugin_v2:FirewallPluginV2
@ -45,6 +44,9 @@ tempest.test_plugins =
neutron-fwaas = neutron_fwaas.tests.tempest_plugin.plugin:NeutronFWaaSPlugin
oslo.config.opts =
firewall.agent = neutron_fwaas.opts:list_agent_opts
neutron.agent.l3.extensions =
fwaas = neutron_fwaas.services.firewall.agents.l3reference.firewall_l3_agent:L3WithFWaaS
fwaas_v2 = neutron_fwaas.services.firewall.agents.l3reference.firewall_l3_agent_v2:L3WithFWaaS
[build_sphinx]
all_files = 1