]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Improve iptables_manager _modify_rules() method
authorSudhakar <sudhakar.gariganti@gmail.com>
Mon, 3 Mar 2014 10:05:20 +0000 (15:35 +0530)
committerBrian Haley <brian.haley@hp.com>
Mon, 2 Jun 2014 20:24:56 +0000 (16:24 -0400)
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

neutron/agent/linux/iptables_manager.py
neutron/tests/unit/test_iptables_manager.py

index 92241ece2cddb39a2502ffaa53a755b4905e1c97..fb0a21ff5bcd02b2216927ef2ab6835ee78d0e52 100644 (file)
@@ -457,6 +457,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
@@ -489,19 +496,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]'
@@ -517,21 +519,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
index af23432bf1045c3fe06b2d8035305919f66845fe..5e16406bd8111c001d21f4ebd19d5680371e7901 100644 (file)
@@ -670,6 +670,30 @@ class IptablesManagerStateFulTestCase(base.BaseTestCase):
 
         tools.verify_mock_calls(self.execute, expected_calls_and_values)
 
+    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):