]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
Replace O(n) with O(1) when TC_INSERT_ENTRY() inserts an entry at the end.
authorMartin Josefsson <gandalf@wlug.westbo.se>
Thu, 23 Sep 2004 19:25:06 +0000 (19:25 +0000)
committerMartin Josefsson <gandalf@wlug.westbo.se>
Thu, 23 Sep 2004 19:25:06 +0000 (19:25 +0000)
Do the same with TC_DELETE_NUM_ENTRY() when deleting the last rule.

My rule management script does both of these things in certain situations.
Created a file with 50.000 rules which my script converted into
iptables-restore format but inserting each rule with an index instead of
appending like the iptables-save output does. That took a while without this
optimization.  Same thing when deleting the 45.000 last rules in that chain,
the script outputs deletes by number starting from the bottom.

Inserting or deleting (by number) in the middle of the chain is still O(n)
where n is the rulenumber where the insert/delete is taking place.

libiptc/libiptc.c

index 71fe90b0e4fd82724271c6d7e68b499300ff0f7d..2ddbc5d865db6768a434c6cf294fb973eab826a2 100644 (file)
@@ -1,4 +1,4 @@
-/* Library which manipulates firewall rules.  Version $Revision: 1.57 $ */
+/* Library which manipulates firewall rules.  Version $Revision: 1.56 $ */
 
 /* Architecture of firewall rules is as follows:
  *
@@ -1262,13 +1262,20 @@ TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
                return 0;
        }
 
-       /* Try to get the rule we want to insert after.
-          In case of no rules, insert after chain head. */
-       r = iptcc_get_rule_num(c, rulenum + 1);
-       if (r)
-               prev = &r->list;
-       else
+       /* If we are inserting at the end just take advantage of the
+          double linked list, insert will happen before the entry
+          prev points to. */
+       if (rulenum == c->num_rules) {
                prev = &c->rules;
+       } else {
+               r = iptcc_get_rule_num(c, rulenum + 1);
+               if (!r) {
+                       /* Shouldn't happen */
+                       errno = ENOENT;
+                       return 0;
+               }
+               prev = &r->list;
+       }
 
        if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
                errno = ENOMEM;
@@ -1497,7 +1504,15 @@ TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
                return 0;
        }
 
-       if (!(r = iptcc_get_rule_num(c, rulenum + 1))) {
+       if (c->num_rules == 0) {
+               errno = E2BIG;
+               return 0;
+       }
+
+       /* Take advantage of the double linked list if possible. */
+       if (rulenum == c->num_rules - 1)
+               r = list_entry(c->rules.prev, struct rule_head, list);
+       else if (!(r = iptcc_get_rule_num(c, rulenum + 1))) {
                errno = E2BIG;
                return 0;
        }