From 0bac74ad534cb1b3204b7771e6a58c4771166bd8 Mon Sep 17 00:00:00 2001 From: laforge Date: Tue, 24 Jun 2003 17:37:21 +0000 Subject: Add my recent performance optimization work, might destabilize iptables. Please report bugs to bugzilla, we need to fix this up before releasing the next iptables version. --- libiptc/libiptc.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 13 deletions(-) diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index 73a3cac..e0cee2d 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -12,9 +12,12 @@ * COPYING for details). * (C) 2000-2003 by the Netfilter Core Team * - * 2003-Jun-20: Harald Welte : * - Reimplementation of chain cache to use offsets instead of entries - * + * 2003-Jun-23: Harald Welte : + * - performance optimization, sponsored by Astaro AG (http://www.astaro.com/) + * don't rebuild the chain cache after every operation, instead fix it + * up after a ruleset change. */ #ifndef IPT_LIB_DIR @@ -100,13 +103,6 @@ STRUCT_TC_HANDLE static void set_changed(TC_HANDLE_T h) { - if (h->cache_chain_heads) { - free(h->cache_chain_heads); - h->cache_chain_heads = NULL; - h->cache_num_chains = 0; - h->cache_chain_iteration = NULL; - h->cache_rule_end = NULL; - } h->changed = 1; } @@ -461,6 +457,77 @@ static int populate_cache(TC_HANDLE_T h) return 1; } +static int +correct_cache(TC_HANDLE_T h, unsigned int offset, int delta) +{ + int i; /* needs to be signed because deleting first + chain can make it drop to -1 */ + + if (!delta) + return 1; + + for (i = 0; i < h->cache_num_chains; i++) { + struct chain_cache *cc = &h->cache_chain_heads[i]; + + if (delta < 0) { + /* take care about deleted chains */ + if (cc->start_off >= offset+delta + && cc->end_off <= offset) { + /* this chain is within the deleted range, + * let's remove it from the cache */ + void *start; + unsigned int size; + + h->cache_num_chains--; + if (i+1 >= h->cache_num_chains) + continue; + start = &h->cache_chain_heads[i+1]; + size = (h->cache_num_chains-i) + * sizeof(struct chain_cache); + memmove(cc, start, size); + + /* iterate over same index again, since + * it is now a different chain */ + i--; + continue; + } + } + + if (cc->start_off > offset) + cc->start_off += delta; + + if (cc->end_off >= offset) + cc->end_off += delta; + } + /* HW_FIXME: sorting might be needed, but just in case a new chain was + * added */ + + return 1; +} + +static int +add_chain_cache(TC_HANDLE_T h, const char *name, unsigned int start_off, + unsigned int end_off) +{ + struct chain_cache *ccs = realloc(h->cache_chain_heads, + (h->new_number / 2 + 4 + 1) + * sizeof(struct chain_cache)); + struct chain_cache *newcc; + + if (!ccs) + return 0; + + h->cache_chain_heads = ccs; + newcc = &h->cache_chain_heads[h->cache_num_chains]; + h->cache_num_chains++; + + strncpy(newcc->name, name, TABLE_MAXNAMELEN-1); + newcc->start_off = start_off; + newcc->end_off = end_off; + + return 1; +} + /* Returns cache ptr if found, otherwise NULL. */ static struct chain_cache * find_label(const char *name, TC_HANDLE_T handle) @@ -706,7 +773,7 @@ TC_GET_POLICY(const char *chain, return target_name(*handle, e); } -static int +static inline int correct_verdict(STRUCT_ENTRY *e, char *base, unsigned int offset, int delta_offset) @@ -807,8 +874,16 @@ insert_rules(unsigned int num_rules, unsigned int rules_size, newh->entries.size = (*handle)->entries.size + rules_size; newh->hooknames = (*handle)->hooknames; - if ((*handle)->cache_chain_heads) - free((*handle)->cache_chain_heads); + newh->cache_chain_heads = (*handle)->cache_chain_heads; + newh->cache_num_builtins = (*handle)->cache_num_builtins; + newh->cache_num_chains = (*handle)->cache_num_chains; + newh->cache_rule_end = (*handle)->cache_rule_end; + newh->cache_chain_iteration = (*handle)->cache_chain_iteration; + if (!correct_cache(newh, offset, rules_size)) { + free(newh); + return 0; + } + free(*handle); *handle = newh; @@ -867,6 +942,10 @@ delete_rules(unsigned int num_rules, unsigned int rules_size, (*handle)->new_number -= num_rules; (*handle)->entries.size -= rules_size; + /* Fix the chain cache */ + if (!correct_cache(*handle, offset, -(int)rules_size)) + return 0; + return set_verdict(offset, -(int)rules_size, handle); } @@ -1370,6 +1449,7 @@ TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) STRUCT_ENTRY ret; STRUCT_STANDARD_TARGET target; } newc; + unsigned int destination; iptc_fn = TC_CREATE_CHAIN; @@ -1407,11 +1487,21 @@ TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) = ALIGN(sizeof(STRUCT_STANDARD_TARGET)); newc.target.verdict = RETURN; + destination = index2offset(*handle, (*handle)->new_number -1); + /* Add just before terminal entry */ ret = insert_rules(2, sizeof(newc), &newc.head, - index2offset(*handle, (*handle)->new_number - 1), + destination, (*handle)->new_number - 1, 0, handle); + + set_changed(*handle); + + /* add chain cache info for this chain */ + add_chain_cache(*handle, chain, + destination+newc.head.next_offset, + destination+newc.head.next_offset); + return ret; } @@ -1539,6 +1629,11 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname, memset(t->error, 0, sizeof(t->error)); strcpy(t->error, newname); + + /* update chain cache */ + memset(c->name, 0, sizeof(c->name)); + strcpy(c->name, newname); + set_changed(*handle); return 1; -- cgit v1.2.3