Preventing iptables rule to be thrashed

When update meter label or rule, iptables_manager will update iptables
rule in router's namespace. In order to, it will clean traffic counter
number collected in interval time, the other iptables always trashing
that will clean old iptalbes rule and generate new same significance
iptables rule.

Change-Id: Ide2b26c98587258175234acded38ce481b7e7f76
Closes-Bug: #1618879
This commit is contained in:
gaozhengwei 2016-08-31 23:11:10 +08:00 committed by Brian Haley
parent 1a4cce9f34
commit 5b7c71a327
4 changed files with 177 additions and 21 deletions

View File

@ -118,7 +118,10 @@ class IptablesRule(object):
chain = '%s-%s' % (self.wrap_name, self.chain)
else:
chain = self.chain
return comment_rule('-A %s %s' % (chain, self.rule), self.comment)
rule = '-A %s %s' % (chain, self.rule)
# If self.rule is '' the above will cause a trailing space, which
# could cause us to not match on save/restore, so strip it now.
return comment_rule(rule.strip(), self.comment)
class IptablesTable(object):

View File

@ -181,9 +181,9 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver):
def _prepare_rule(self, ext_dev, rule, label_chain):
remote_ip = rule['remote_ip_prefix']
if rule['direction'] == 'egress':
dir_opt = '-o %s -d %s' % (ext_dev, remote_ip)
dir_opt = '-d %s -o %s' % (remote_ip, ext_dev)
else:
dir_opt = '-i %s -s %s' % (ext_dev, remote_ip)
dir_opt = '-s %s -i %s' % (remote_ip, ext_dev)
if rule['excluded']:
ipt_rule = '%s -j RETURN' % dir_opt

View File

@ -132,6 +132,50 @@ TRAFFIC_COUNTERS_DUMP = (
' 400 65901 chain2 all -- * * 0.0.0.0/0'
' 0.0.0.0/0 \n')
FILTER_RESTORE_DUMP = ('# Generated by iptables_manager\n'
'*filter\n'
':FORWARD - [0:0]\n'
':INPUT - [0:0]\n'
':OUTPUT - [0:0]\n'
':neutron-filter-top - [0:0]\n'
':%(bn)s-FORWARD - [0:0]\n'
':%(bn)s-INPUT - [0:0]\n'
':%(bn)s-OUTPUT - [0:0]\n'
':%(bn)s-test-filter - [0:0]\n'
':%(bn)s-local - [0:0]\n'
'-A FORWARD -j neutron-filter-top\n'
'-A FORWARD -j %(bn)s-FORWARD\n'
'-A INPUT -j %(bn)s-INPUT\n'
'-A OUTPUT -j neutron-filter-top\n'
'-A OUTPUT -j %(bn)s-OUTPUT\n'
'-A neutron-filter-top -j %(bn)s-local\n'
'%(filter_rules)s'
'COMMIT\n'
'# Completed by iptables_manager\n')
NAT_RESTORE_TEMPLATE = ('# Generated by iptables_manager\n'
'*nat\n'
':OUTPUT - [0:0]\n'
':POSTROUTING - [0:0]\n'
':PREROUTING - [0:0]\n'
':neutron-postrouting-bottom - [0:0]\n'
':%(bn)s-OUTPUT - [0:0]\n'
':%(bn)s-POSTROUTING - [0:0]\n'
':%(bn)s-PREROUTING - [0:0]\n'
':%(bn)s-float-snat - [0:0]\n'
':%(bn)s-snat - [0:0]\n'
'-A OUTPUT -j %(bn)s-OUTPUT\n'
'-A POSTROUTING -j %(bn)s-POSTROUTING\n'
'-A POSTROUTING -j neutron-postrouting-bottom\n'
'-A PREROUTING -j %(bn)s-PREROUTING\n'
'-A neutron-postrouting-bottom -j %(bn)s-snat\n'
'-A %(bn)s-snat -j '
'%(bn)s-float-snat\n'
'COMMIT\n'
'# Completed by iptables_manager\n')
NAT_RESTORE_DUMP = NAT_RESTORE_TEMPLATE % IPTABLES_ARG
class IptablesTestCase(base.BaseTestCase):
@ -281,9 +325,47 @@ def _generate_raw_dump(iptables_args):
'# Completed by iptables_manager\n' % iptables_args)
def _generate_mangle_restore_dump(iptables_args):
return ('# Generated by iptables_manager\n'
'*mangle\n'
':FORWARD - [0:0]\n'
':INPUT - [0:0]\n'
':OUTPUT - [0:0]\n'
':POSTROUTING - [0:0]\n'
':PREROUTING - [0:0]\n'
':%(bn)s-FORWARD - [0:0]\n'
':%(bn)s-INPUT - [0:0]\n'
':%(bn)s-OUTPUT - [0:0]\n'
':%(bn)s-POSTROUTING - [0:0]\n'
':%(bn)s-PREROUTING - [0:0]\n'
':%(bn)s-mark - [0:0]\n'
'-A FORWARD -j %(bn)s-FORWARD\n'
'-A INPUT -j %(bn)s-INPUT\n'
'-A OUTPUT -j %(bn)s-OUTPUT\n'
'-A POSTROUTING -j %(bn)s-POSTROUTING\n'
'-A PREROUTING -j %(bn)s-PREROUTING\n'
'-A %(bn)s-PREROUTING -j %(bn)s-mark\n'
'COMMIT\n'
'# Completed by iptables_manager\n' % iptables_args)
def _generate_raw_restore_dump(iptables_args):
return ('# Generated by iptables_manager\n'
'*raw\n'
':OUTPUT - [0:0]\n'
':PREROUTING - [0:0]\n'
':%(bn)s-OUTPUT - [0:0]\n'
':%(bn)s-PREROUTING - [0:0]\n'
'-A OUTPUT -j %(bn)s-OUTPUT\n'
'-A PREROUTING -j %(bn)s-PREROUTING\n'
'COMMIT\n'
'# Completed by iptables_manager\n' % iptables_args)
MANGLE_DUMP = _generate_mangle_dump(IPTABLES_ARG)
MANGLE_DUMP_V6 = _generate_mangle_dump_v6(IPTABLES_ARG)
RAW_DUMP = _generate_raw_dump(IPTABLES_ARG)
MANGLE_RESTORE_DUMP = _generate_mangle_restore_dump(IPTABLES_ARG)
RAW_RESTORE_DUMP = _generate_raw_restore_dump(IPTABLES_ARG)
class IptablesManagerStateFulTestCase(base.BaseTestCase):
@ -1086,6 +1168,77 @@ class IptablesManagerStateFulTestCase(base.BaseTestCase):
def test_get_traffic_counters_with_zero_with_ipv6(self):
self._test_get_traffic_counters_with_zero_helper(True)
def test_add_blank_rule(self):
self.iptables = iptables_manager.IptablesManager(
use_ipv6=False)
self.execute = mock.patch.object(self.iptables, "execute").start()
iptables_args = {}
iptables_args.update(IPTABLES_ARG)
filter_rules = ('-A %(bn)s-test-filter\n' % iptables_args)
iptables_args['filter_rules'] = filter_rules
filter_dump_mod = FILTER_RESTORE_DUMP % iptables_args
expected_calls_and_values = [
(mock.call(['iptables-save'],
run_as_root=True),
(filter_dump_mod + MANGLE_RESTORE_DUMP +
NAT_RESTORE_DUMP + RAW_RESTORE_DUMP)),
]
tools.setup_mock_calls(self.execute, expected_calls_and_values)
self.iptables.ipv4['filter'].add_chain('test-filter')
self.iptables.ipv4['filter'].add_rule('test-filter', '')
self.iptables.apply()
tools.verify_mock_calls(self.execute, expected_calls_and_values)
def test_add_rule_exchanged_interface_and_ip(self):
self.iptables = iptables_manager.IptablesManager(
use_ipv6=False)
self.execute = mock.patch.object(self.iptables, "execute").start()
iptables_args = {}
iptables_args.update(IPTABLES_ARG)
filter_rules = ('-A %(bn)s-test-filter -d 192.168.0.2 -i tap-xxx '
'-j ACCEPT\n'
% iptables_args)
iptables_args['filter_rules'] = filter_rules
filter_dump_mod = FILTER_RESTORE_DUMP % iptables_args
RESTORE_INPUT = ('# Generated by iptables_manager\n'
'*filter\n'
'-D run.py-test-filter 1\n'
'-I run.py-test-filter 1 '
'-i tap-xxx -d 192.168.0.2 -j ACCEPT\n'
'COMMIT\n'
'# Completed by iptables_manager\n'
% IPTABLES_ARG)
expected_calls_and_values = [
(mock.call(['iptables-save'],
run_as_root=True),
(filter_dump_mod + MANGLE_RESTORE_DUMP +
NAT_RESTORE_DUMP + RAW_RESTORE_DUMP)),
(mock.call(['iptables-restore', '-n'],
process_input=RESTORE_INPUT,
run_as_root=True),
None),
]
tools.setup_mock_calls(self.execute, expected_calls_and_values)
self.iptables.ipv4['filter'].add_chain('test-filter')
self.iptables.ipv4['filter'].add_rule('test-filter',
'-i tap-xxx -d 192.168.0.2 '
'-j ACCEPT')
self.iptables.apply()
tools.verify_mock_calls(self.execute, expected_calls_and_values)
class IptablesManagerStateLessTestCase(base.BaseTestCase):

View File

@ -146,7 +146,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 10.0.0.0/24'
'-s 10.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False),
mock.call.add_chain('neutron-meter-l-eeef45da-c60',
@ -160,7 +160,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-eeef45da-c60',
'-o qg-7d411f48-ec -d 20.0.0.0/24'
'-d 20.0.0.0/24 -o qg-7d411f48-ec'
' -j neutron-meter-l-eeef45da-c60',
wrap=False, top=False)]
@ -215,7 +215,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 10.0.0.0/24'
'-s 10.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False),
mock.call.add_chain('neutron-meter-l-eeef45da-c60',
@ -229,7 +229,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-eeef45da-c60',
'-i qg-7d411f48-ec -s 20.0.0.0/24'
'-s 20.0.0.0/24 -i qg-7d411f48-ec'
' -j RETURN',
wrap=False, top=True)]
@ -266,17 +266,17 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 10.0.0.0/24'
'-s 10.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False),
mock.call.empty_chain('neutron-meter-r-c5df2fe5-c60',
wrap=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-o qg-6d411f48-ec -d 10.0.0.0/24'
'-d 10.0.0.0/24 -o qg-6d411f48-ec'
' -j RETURN',
wrap=False, top=True),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 20.0.0.0/24 -j '
'-s 20.0.0.0/24 -i qg-6d411f48-ec -j '
'neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False)]
@ -308,17 +308,17 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 10.0.0.0/24'
'-s 10.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 20.0.0.0/24'
'-s 20.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False),
mock.call.empty_chain('neutron-meter-r-c5df2fe5-c60',
wrap=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 10.0.0.0/24'
'-s 10.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False)]
@ -330,11 +330,11 @@ class IptablesDriverTestCase(base.BaseTestCase):
self.metering.add_metering_label_rule(None, new_routers_rules)
calls = [
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 30.0.0.0/24'
'-s 30.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False),
mock.call.add_rule('neutron-meter-r-eeef45da-c60',
'-o qg-7d411f48-ec -d 40.0.0.0/24'
'-d 40.0.0.0/24 -o qg-7d411f48-ec'
' -j neutron-meter-l-eeef45da-c60',
wrap=False, top=False),
@ -348,11 +348,11 @@ class IptablesDriverTestCase(base.BaseTestCase):
self.metering.remove_metering_label_rule(None, new_routers_rules)
calls = [
mock.call.remove_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 30.0.0.0/24'
'-s 30.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False),
mock.call.remove_rule('neutron-meter-r-eeef45da-c60',
'-o qg-7d411f48-ec -d 40.0.0.0/24'
'-d 40.0.0.0/24 -o qg-7d411f48-ec'
' -j neutron-meter-l-eeef45da-c60',
wrap=False, top=False)
]
@ -374,7 +374,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 10.0.0.0/24'
'-s 10.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False),
mock.call.remove_chain('neutron-meter-l-c5df2fe5-c60',
@ -408,7 +408,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-6d411f48-ec -s 10.0.0.0/24'
'-s 10.0.0.0/24 -i qg-6d411f48-ec'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False),
mock.call.add_chain('neutron-meter-l-eeef45da-c60',
@ -422,7 +422,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-eeef45da-c60',
'-i qg-7d411f48-ec -s 20.0.0.0/24'
'-s 20.0.0.0/24 -i qg-7d411f48-ec'
' -j RETURN',
wrap=False, top=True),
mock.call.remove_chain('neutron-meter-l-c5df2fe5-c60',
@ -440,7 +440,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
'',
wrap=False),
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
'-i qg-587b63c1-22 -s 10.0.0.0/24'
'-s 10.0.0.0/24 -i qg-587b63c1-22'
' -j neutron-meter-l-c5df2fe5-c60',
wrap=False, top=False)]