Browse Source

Improve iptables_manager _modify_rules() method

As the number of ports per default security group increases, the
number of iptables entries on the Compute Node grows.  Because of
this, there is a gradual increase in the time taken to apply chains
and rules.

Currently we are using list comprehensions to find if a new chain or
rule matches an existing one.  Instead, walk through the list in
reverse to find a matching entry.

Added a new method, _find_last_entry(), to return the entry we are
searching for.

Change-Id: I3585479ffa00be556b8b21dc9dbd6b36ad37f4de
Closes-Bug: #1302272
Related-Bug: #1253993
(cherry picked from commit 0c202ab3e4)
tags/2013.2.4
Sudhakar 5 years ago
parent
commit
3a7df5c819
2 changed files with 43 additions and 21 deletions
  1. +19
    -21
      neutron/agent/linux/iptables_manager.py
  2. +24
    -0
      neutron/tests/unit/test_iptables_manager.py

+ 19
- 21
neutron/agent/linux/iptables_manager.py View File

@@ -411,6 +411,13 @@ class IptablesManager(object):

return rules_index

def _find_last_entry(self, filter_list, match_str):
# find a matching entry, starting from the bottom
for s in reversed(filter_list):
s = s.strip()
if match_str in s:
return s

def _modify_rules(self, current_lines, table, table_name):
unwrapped_chains = table.unwrapped_chains
chains = table.chains
@@ -443,19 +450,14 @@ class IptablesManager(object):
for chain in all_chains:
chain_str = str(chain).strip()

orig_filter = [s for s in old_filter if chain_str in s.strip()]
dup_filter = [s for s in new_filter if chain_str in s.strip()]
old = self._find_last_entry(old_filter, chain_str)
if not old:
dup = self._find_last_entry(new_filter, chain_str)
new_filter = [s for s in new_filter if chain_str not in s.strip()]

# if no old or duplicates, use original chain
if orig_filter:
# grab the last entry, if there is one
old = orig_filter[-1]
chain_str = str(old).strip()
elif dup_filter:
# grab the last entry, if there is one
dup = dup_filter[-1]
chain_str = str(dup).strip()
if old or dup:
chain_str = str(old or dup)
else:
# add-on the [packet:bytes]
chain_str += ' - [0:0]'
@@ -471,21 +473,17 @@ class IptablesManager(object):
# Further down, we weed out duplicates from the bottom of the
# list, so here we remove the dupes ahead of time.

orig_filter = [s for s in old_filter if rule_str in s.strip()]
dup_filter = [s for s in new_filter if rule_str in s.strip()]
old = self._find_last_entry(old_filter, rule_str)
if not old:
dup = self._find_last_entry(new_filter, rule_str)
new_filter = [s for s in new_filter if rule_str not in s.strip()]

# if no old or duplicates, use original rule
if orig_filter:
# grab the last entry, if there is one
old = orig_filter[-1]
rule_str = str(old).strip()
elif dup_filter:
# grab the last entry, if there is one
dup = dup_filter[-1]
rule_str = str(dup).strip()
if old or dup:
rule_str = str(old or dup)
# backup one index so we write the array correctly
rules_index -= 1
if not old:
rules_index -= 1
else:
# add-on the [packet:bytes]
rule_str = '[0:0] ' + rule_str

+ 24
- 0
neutron/tests/unit/test_iptables_manager.py View File

@@ -553,6 +553,30 @@ class IptablesManagerStateFulTestCase(base.BaseTestCase):

self.mox.VerifyAll()

def _test_find_last_entry(self, find_str):
filter_list = [':neutron-filter-top - [0:0]',
':%(bn)s-FORWARD - [0:0]',
':%(bn)s-INPUT - [0:0]',
':%(bn)s-local - [0:0]',
':%(wrap)s - [0:0]',
':%(bn)s-OUTPUT - [0:0]',
'[0:0] -A FORWARD -j neutron-filter-top',
'[0:0] -A OUTPUT -j neutron-filter-top'
% IPTABLES_ARG]

return self.iptables._find_last_entry(filter_list, find_str)

def test_find_last_entry_old_dup(self):
find_str = 'neutron-filter-top'
match_str = '[0:0] -A OUTPUT -j neutron-filter-top'
ret_str = self._test_find_last_entry(find_str)
self.assertEqual(ret_str, match_str)

def test_find_last_entry_none(self):
find_str = 'neutron-filter-NOTFOUND'
ret_str = self._test_find_last_entry(find_str)
self.assertIsNone(ret_str)


class IptablesManagerStateLessTestCase(base.BaseTestCase):


Loading…
Cancel
Save