Enable to use conntrack driver in fwaas_v2

The conntrack entries management codes were identical in fwaas and
fwaas_v2 drivers. However [1] didn't handle the fwaas_v2 driver's part.

[1] Id0597f74bef67b85776445e7bc591eb085f55acc

Related-Bug: #1664294
Change-Id: I4a444fb313bbef2d3a410703ea06d2a0605df772
This commit is contained in:
Hunt Xu 2017-08-02 16:56:13 +08:00
parent f4e3d9cc69
commit 24b25ccfbe
4 changed files with 107 additions and 108 deletions

View File

@ -17,6 +17,26 @@ import abc
import six
from neutron_lib.utils import runtime
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
LOG = logging.getLogger(__name__)
def load_and_init_conntrack_driver(*args, **kwargs):
driver = cfg.CONF.fwaas.conntrack_driver
try:
conntrack_driver_cls = runtime.load_class_by_alias_or_classname(
'neutron_fwaas.services.firewall.drivers.linux', driver)
except ImportError:
with excutils.save_and_reraise_exception():
LOG.exception("Driver '%s' not found.", driver)
conntrack_driver = conntrack_driver_cls()
conntrack_driver.initialize(*args, **kwargs)
return conntrack_driver
@six.add_metaclass(abc.ABCMeta)
class ConntrackDriverBase(object):

View File

@ -16,12 +16,10 @@
from neutron.agent.linux import iptables_manager
from neutron.common import utils
from neutron_lib.exceptions import firewall_v1 as f_exc
from neutron_lib.utils import runtime
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
from neutron_fwaas.common import fwaas_constants as f_const
from neutron_fwaas.services.firewall.drivers import conntrack_base
from neutron_fwaas.services.firewall.drivers import fwaas_base
@ -59,27 +57,7 @@ class IptablesFwaasDriver(fwaas_base.FwaasDriverBase):
def __init__(self):
LOG.debug("Initializing fwaas iptables driver")
self.pre_firewall = None
conntrack_cls = self._load_firewall_extension_driver(
'neutron_fwaas.services.firewall.drivers.linux',
cfg.CONF.fwaas.conntrack_driver)
self.conntrack = conntrack_cls()
self.conntrack.initialize()
@staticmethod
def _load_firewall_extension_driver(namespace, driver):
"""Loads driver using alias or class name
:param namespace: namespace where alias is defined
:param driver: driver alias or class name
:returns driver that is loaded
:raises ImportError if fails to load driver
"""
try:
return runtime.load_class_by_alias_or_classname(
namespace, driver)
except ImportError:
with excutils.save_and_reraise_exception():
LOG.error("Driver '%s' not found.", driver)
self.conntrack = conntrack_base.load_and_init_conntrack_driver()
def create_firewall(self, agent_mode, apply_list, firewall):
LOG.debug('Creating firewall %(fw_id)s for tenant %(tid)s',

View File

@ -14,11 +14,11 @@
# under the License.
from neutron.agent.linux import iptables_manager
from neutron.agent.linux import utils as linux_utils
from neutron.common import utils
from neutron_lib.exceptions import firewall_v2 as fw_ext
from oslo_log import log as logging
from neutron_fwaas.services.firewall.drivers import conntrack_base
from neutron_fwaas.services.firewall.drivers import fwaas_base_v2
LOG = logging.getLogger(__name__)
@ -57,6 +57,7 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
def __init__(self):
LOG.debug("Initializing fwaas iptables driver")
self.pre_firewall = None
self.conntrack = conntrack_base.load_and_init_conntrack_driver()
def _get_intf_name(self, if_prefix, port_id):
_name = "%s%s" % (if_prefix, port_id)
@ -275,25 +276,6 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
def _find_new_rules(self, pre_firewall, firewall):
return self._find_removed_rules(firewall, pre_firewall)
def _get_conntrack_cmd_from_rule(self, ipt_mgr, rule=None):
prefixcmd = ['ip', 'netns', 'exec'] + [ipt_mgr.namespace]
cmd = ['conntrack', '-D']
if rule:
conntrack_filter = self._get_conntrack_filter_from_rule(rule)
exec_cmd = prefixcmd + cmd + conntrack_filter
else:
exec_cmd = prefixcmd + cmd
return exec_cmd
def _remove_conntrack_by_cmd(self, cmd):
if cmd:
try:
linux_utils.execute(cmd, run_as_root=True,
check_exit_code=True,
extra_ok_codes=[1])
except RuntimeError:
LOG.exception("Failed execute conntrack command %s", str(cmd))
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]))
@ -302,8 +284,7 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
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)
self._remove_conntrack_by_cmd(cmd)
self.conntrack.flush_entries(ipt_mgr.namespace)
def _remove_conntrack_updated_firewall(self, agent_mode,
apply_list, pre_firewall, firewall):
@ -319,27 +300,8 @@ class IptablesFwaasDriver(fwaas_base_v2.FwaasDriverBase):
i_rules = self._find_new_rules(pre_firewall, firewall)
r_rules = self._find_removed_rules(pre_firewall, firewall)
removed_conntrack_rules_list = ch_rules + i_rules + r_rules
for rule in removed_conntrack_rules_list:
cmd = self._get_conntrack_cmd_from_rule(ipt_mgr, rule)
self._remove_conntrack_by_cmd(cmd)
def _get_conntrack_filter_from_rule(self, rule):
"""Get conntrack filter from rule.
The key for get conntrack filter is protocol, destination_port
and source_port. If we want to take more keys, add to the list.
"""
conntrack_filter = []
keys = [['-p', 'protocol'], ['-f', 'ip_version'],
['--dport', 'destination_port'], ['--sport', 'source_port']]
for key in keys:
if rule.get(key[1]):
if key[1] == 'ip_version':
conntrack_filter.append(key[0])
conntrack_filter.append('ipv' + str(rule.get(key[1])))
else:
conntrack_filter.append(key[0])
conntrack_filter.append(rule.get(key[1]))
return conntrack_filter
self.conntrack.delete_entries(removed_conntrack_rules_list,
ipt_mgr.namespace)
def _remove_default_chains(self, nsid):
"""Remove fwaas default policy chain."""

View File

@ -37,13 +37,12 @@ MAX_INTF_NAME_LEN = 14
class IptablesFwaasTestCase(base.BaseTestCase):
def setUp(self):
super(IptablesFwaasTestCase, self).setUp()
self.utils_exec_p = mock.patch(
'neutron.agent.linux.utils.execute')
self.utils_exec = self.utils_exec_p.start()
self.iptables_cls_p = mock.patch(
'neutron.agent.linux.iptables_manager.IptablesManager')
self.iptables_cls_p.start()
self.firewall = fwaas.IptablesFwaasDriver()
self.firewall.conntrack.delete_entries = mock.Mock()
self.firewall.conntrack.flush_entries = mock.Mock()
def _fake_rules_v4(self, fwid, apply_list):
rule_list = []
@ -304,11 +303,8 @@ class IptablesFwaasTestCase(base.BaseTestCase):
self.firewall.create_firewall_group(FW_LEGACY, apply_list, firewall)
for router_info_inst, port_ids in apply_list:
namespace = router_info_inst.iptables_manager.namespace
cmd = ['ip', 'netns', 'exec', namespace, 'conntrack', '-D']
calls = [
mock.call(cmd, run_as_root=True, check_exit_code=True,
extra_ok_codes=[1])]
self.utils_exec.assert_has_calls(calls)
calls = [mock.call(namespace)]
self.firewall.conntrack.flush_entries.assert_has_calls(calls)
def test_remove_conntrack_inserted_rule(self):
apply_list = self._fake_apply_list()
@ -324,18 +320,35 @@ class IptablesFwaasTestCase(base.BaseTestCase):
rule_list.insert(2, insert_rule)
firewall = self._fake_firewall(rule_list)
self.firewall.update_firewall_group(FW_LEGACY, apply_list, firewall)
rules_changed = [
{'destination_port': '23',
'position': '2',
'protocol': 'tcp',
'ip_version': 4,
'enabled': True,
'action': 'reject',
'id': 'fake-fw-rule3'},
{'destination_port': '23',
'position': '3',
'protocol': 'tcp',
'ip_version': 4,
'enabled': True,
'action': 'reject',
'id': 'fake-fw-rule3'}
] * 2 # Egress and ingress rule lists
rules_inserted = [
{'id': 'fake-fw-rule',
'protocol': 'icmp',
'ip_version': 4,
'enabled': True,
'action': 'deny',
'position': '2'}
] * 2 # Egress and ingress rule lists
for router_info_inst, port_ids in apply_list:
namespace = router_info_inst.iptables_manager.namespace
cmd1 = ['ip', 'netns', 'exec', namespace, 'conntrack',
'-D', '-p', 'tcp', '-f', 'ipv4', '--dport', '23']
cmd2 = ['ip', 'netns', 'exec', namespace, 'conntrack',
'-D', '-p', 'icmp', '-f', 'ipv4']
calls = [
mock.call(cmd1, run_as_root=True, check_exit_code=True,
extra_ok_codes=[1]),
mock.call(cmd2, run_as_root=True, check_exit_code=True,
extra_ok_codes=[1])]
self.utils_exec.assert_has_calls(calls)
self.firewall.conntrack.delete_entries.assert_called_once_with(
rules_changed + rules_inserted, namespace
)
def test_remove_conntrack_removed_rule(self):
apply_list = self._fake_apply_list()
@ -347,18 +360,36 @@ class IptablesFwaasTestCase(base.BaseTestCase):
rule_list.remove(remove_rule)
firewall = self._fake_firewall(rule_list)
self.firewall.update_firewall_group(FW_LEGACY, apply_list, firewall)
rules_changed = [
{'destination_port': '23',
'position': '2',
'protocol': 'tcp',
'ip_version': 4,
'enabled': True,
'action': 'reject',
'id': 'fake-fw-rule3'},
{'destination_port': '23',
'position': '1',
'protocol': 'tcp',
'ip_version': 4,
'enabled': True,
'action': 'reject',
'id': 'fake-fw-rule3'}
] * 2 # Egress and ingress rule lists
rules_removed = [
{'enabled': True,
'position': '1',
'protocol': 'tcp',
'id': 'fake-fw-rule2',
'ip_version': 4,
'action': 'deny',
'destination_port': '22'}
] * 2 # Egress and ingress rule lists
for router_info_inst, port_ids in apply_list:
namespace = router_info_inst.iptables_manager.namespace
cmd1 = ['ip', 'netns', 'exec', namespace, 'conntrack',
'-D', '-p', 'tcp', '-f', 'ipv4', '--dport', '23']
cmd2 = ['ip', 'netns', 'exec', namespace, 'conntrack',
'-D', '-p', 'tcp', '-f', 'ipv4', '--dport', '22']
calls = [
mock.call(cmd1, run_as_root=True, check_exit_code=True,
extra_ok_codes=[1]),
mock.call(cmd2, run_as_root=True, check_exit_code=True,
extra_ok_codes=[1])]
self.utils_exec.assert_has_calls(calls)
self.firewall.conntrack.delete_entries.assert_called_once_with(
rules_changed + rules_removed, namespace
)
def test_remove_conntrack_changed_rule(self):
apply_list = self._fake_apply_list()
@ -368,20 +399,28 @@ class IptablesFwaasTestCase(base.BaseTestCase):
income_rule = {'enabled': True,
'action': 'deny',
'ip_version': 4,
'protocol': 'icmp',
'id': 'fake-fw-rule2'}
rule_list[1] = income_rule
'protocol': 'tcp',
'id': 'fake-fw-rule3'}
rule_list[2] = income_rule
firewall = self._fake_firewall(rule_list)
self.firewall.update_firewall_group(FW_LEGACY, apply_list, firewall)
rules_changed = [
{'id': 'fake-fw-rule3',
'enabled': True,
'action': 'reject',
'position': '2',
'destination_port': '23',
'ip_version': 4,
'protocol': 'tcp'},
{'position': '2',
'enabled': True,
'action': 'deny',
'id': 'fake-fw-rule3',
'ip_version': 4,
'protocol': 'tcp'}
] * 2 # Egress and ingress rule lists
for router_info_inst, port_ids in apply_list:
namespace = router_info_inst.iptables_manager.namespace
cmd1 = ['ip', 'netns', 'exec', namespace, 'conntrack', '-D',
'-p', 'tcp', '-f', 'ipv4', '--dport', '22']
cmd2 = ['ip', 'netns', 'exec', namespace, 'conntrack', '-D',
'-p', 'icmp', '-f', 'ipv4']
calls = [
mock.call(cmd1, run_as_root=True, check_exit_code=True,
extra_ok_codes=[1]),
mock.call(cmd2, run_as_root=True, check_exit_code=True,
extra_ok_codes=[1])]
self.utils_exec.assert_has_calls(calls)
self.firewall.conntrack.delete_entries.assert_called_once_with(
rules_changed, namespace
)