summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rw-r--r--include/Makefile.am2
-rw-r--r--include/alarm.h26
-rw-r--r--include/linux_rbtree.h160
-rw-r--r--src/Makefile.am2
-rw-r--r--src/alarm.c156
-rw-r--r--src/cache_timer.c12
-rw-r--r--src/rbtree.c389
-rw-r--r--src/run.c6
-rw-r--r--src/sync-alarm.c10
-rw-r--r--src/sync-ftfw.c4
11 files changed, 631 insertions, 138 deletions
diff --git a/ChangeLog b/ChangeLog
index 4cd5eff..dc4efab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -39,7 +39,7 @@ o rename class `buffer' to `queue' which is what it really implements
o fix logfiles permissions, do not default to umask
o wake up the daemon iff there are real events to handle instead of polling
o add support for tagged vlan interfaces in the config file, e.g. eth0.1
-o improve alarm framework based on suggestions from Max Kellerman
+o implement a rb-tree based alarm framework
o constify queue_iterate()
o use list_del_init() and list_empty() to check if a node is in the list
o remove unix socket file on exit
diff --git a/include/Makefile.am b/include/Makefile.am
index e8e7f81..d7f27a9 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,5 +1,5 @@
-noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \
+noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \
sync.h conntrackd.h local.h us-conntrack.h \
debug.h log.h hash.h mcast.h conntrack.h \
state_helper.h network.h ignore.h queue.h \
diff --git a/include/alarm.h b/include/alarm.h
index e3e08c1..38aaa01 100644
--- a/include/alarm.h
+++ b/include/alarm.h
@@ -1,30 +1,28 @@
-#ifndef _TIMER_H_
-#define _TIMER_H_
+#ifndef _ALARM_H_
+#define _ALARM_H_
+#include "linux_rbtree.h"
#include "linux_list.h"
#include <sys/time.h>
-struct alarm_list {
- struct list_head head;
+struct alarm_block {
+ struct rb_node node;
+ struct list_head list;
struct timeval tv;
void *data;
- void (*function)(struct alarm_list *a, void *data);
+ void (*function)(struct alarm_block *a, void *data);
};
-int init_alarm_hash(void);
-
-void destroy_alarm_hash(void);
-
-void init_alarm(struct alarm_list *t,
+void init_alarm(struct alarm_block *t,
void *data,
- void (*fcn)(struct alarm_list *a, void *data));
+ void (*fcn)(struct alarm_block *a, void *data));
-void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc);
+void add_alarm(struct alarm_block *alarm, unsigned long sc, unsigned long usc);
-void del_alarm(struct alarm_list *alarm);
+void del_alarm(struct alarm_block *alarm);
-int alarm_pending(struct alarm_list *alarm);
+int alarm_pending(struct alarm_block *alarm);
struct timeval *
get_next_alarm_run(struct timeval *next_alarm);
diff --git a/include/linux_rbtree.h b/include/linux_rbtree.h
new file mode 100644
index 0000000..ee98891
--- /dev/null
+++ b/include/linux_rbtree.h
@@ -0,0 +1,160 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/include/linux/rbtree.h
+
+ To use rbtrees you'll have to implement your own insert and search cores.
+ This will avoid us to use callbacks and to drop drammatically performances.
+ I know it's not the cleaner way, but in C (not in C++) to get
+ performances and genericity...
+
+ Some example of insert and search follows here. The search is a plain
+ normal search over an ordered tree. The insert instead must be implemented
+ int two steps: as first thing the code must insert the element in
+ order as a red leaf in the tree, then the support library function
+ rb_insert_color() must be called. Such function will do the
+ not trivial work to rebalance the rbtree if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+ unsigned long offset)
+{
+ struct rb_node * n = inode->i_rb_page_cache.rb_node;
+ struct page * page;
+
+ while (n)
+ {
+ page = rb_entry(n, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ n = n->rb_left;
+ else if (offset > page->offset)
+ n = n->rb_right;
+ else
+ return page;
+ }
+ return NULL;
+}
+
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+ struct rb_node * parent = NULL;
+ struct page * page;
+
+ while (*p)
+ {
+ parent = *p;
+ page = rb_entry(parent, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ p = &(*p)->rb_left;
+ else if (offset > page->offset)
+ p = &(*p)->rb_right;
+ else
+ return page;
+ }
+
+ rb_link_node(node, parent, p);
+
+ return NULL;
+}
+
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct page * ret;
+ if ((ret = __rb_insert_page_cache(inode, offset, node)))
+ goto out;
+ rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+ return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef _LINUX_RBTREE_H
+#define _LINUX_RBTREE_H
+
+#include <stdlib.h>
+
+struct rb_node
+{
+ unsigned long rb_parent_color;
+#define RB_RED 0
+#define RB_BLACK 1
+ struct rb_node *rb_right;
+ struct rb_node *rb_left;
+} __attribute__((aligned(sizeof(long))));
+ /* The alignment might seem pointless, but allegedly CRIS needs it */
+
+struct rb_root
+{
+ struct rb_node *rb_node;
+};
+
+
+#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
+#define rb_color(r) ((r)->rb_parent_color & 1)
+#define rb_is_red(r) (!rb_color(r))
+#define rb_is_black(r) rb_color(r)
+#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
+#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
+
+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
+}
+static inline void rb_set_color(struct rb_node *rb, int color)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
+}
+
+#define RB_ROOT { NULL, }
+#define rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
+#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(struct rb_node *);
+extern struct rb_node *rb_prev(struct rb_node *);
+extern struct rb_node *rb_first(struct rb_root *);
+extern struct rb_node *rb_last(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+ struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
+ struct rb_node ** rb_link)
+{
+ node->rb_parent_color = (unsigned long )parent;
+ node->rb_left = node->rb_right = NULL;
+
+ *rb_link = node;
+}
+
+#endif /* _LINUX_RBTREE_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 15628b7..7274a14 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,7 +10,7 @@ conntrack_SOURCES = conntrack.c
conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la
conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@
-conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c \
+conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \
local.c log.c mcast.c netlink.c \
ignore_pool.c \
cache.c cache_iterators.c \
diff --git a/src/alarm.c b/src/alarm.c
index 4b23bd1..5013735 100644
--- a/src/alarm.c
+++ b/src/alarm.c
@@ -1,5 +1,5 @@
/*
- * (C) 2006 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2006-2008 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,41 +17,45 @@
*/
#include "alarm.h"
-#include "jhash.h"
#include <stdlib.h>
#include <limits.h>
-#define ALARM_HASH_SIZE 2048
+static struct rb_root alarm_root = RB_ROOT;
+static LIST_HEAD(alarm_run_queue);
-static struct list_head *alarm_hash;
-
-void init_alarm(struct alarm_list *t,
+void init_alarm(struct alarm_block *t,
void *data,
- void (*fcn)(struct alarm_list *a, void *data))
+ void (*fcn)(struct alarm_block *a, void *data))
{
/* initialize the head to check whether a node is inserted */
- INIT_LIST_HEAD(&t->head);
+ RB_CLEAR_NODE(&t->node);
timerclear(&t->tv);
t->data = data;
t->function = fcn;
}
-static void
-__add_alarm(struct alarm_list *alarm)
+static void __add_alarm(struct alarm_block *alarm)
{
- struct alarm_list *t;
- int i = jhash(alarm, sizeof(alarm), 0) % ALARM_HASH_SIZE;
+ struct rb_node **new = &(alarm_root.rb_node);
+ struct rb_node *parent = NULL;
- list_for_each_entry(t, &alarm_hash[i], head) {
- if (timercmp(&alarm->tv, &t->tv, <)) {
- list_add_tail(&alarm->head, &t->head);
- return;
- }
+ while (*new) {
+ struct alarm_block *this;
+
+ this = container_of(*new, struct alarm_block, node);
+
+ parent = *new;
+ if (timercmp(&alarm->tv, &this->tv, <))
+ new = &((*new)->rb_left);
+ else
+ new = &((*new)->rb_right);
}
- list_add_tail(&alarm->head, &alarm_hash[i]);
+
+ rb_link_node(&alarm->node, parent, new);
+ rb_insert_color(&alarm->node, &alarm_root);
}
-void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc)
+void add_alarm(struct alarm_block *alarm, unsigned long sc, unsigned long usc)
{
struct timeval tv;
@@ -63,16 +67,18 @@ void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc)
__add_alarm(alarm);
}
-void del_alarm(struct alarm_list *alarm)
+void del_alarm(struct alarm_block *alarm)
{
/* don't remove a non-inserted node */
- if (!list_empty(&alarm->head))
- list_del_init(&alarm->head);
+ if (!RB_EMPTY_NODE(&alarm->node)) {
+ rb_erase(&alarm->node, &alarm_root);
+ RB_CLEAR_NODE(&alarm->node);
+ }
}
-int alarm_pending(struct alarm_list *alarm)
+int alarm_pending(struct alarm_block *alarm)
{
- if (list_empty(&alarm->head))
+ if (RB_EMPTY_NODE(&alarm->node))
return 0;
return 1;
@@ -99,101 +105,47 @@ calculate_next_run(struct timeval *cand,
struct timeval *
get_next_alarm_run(struct timeval *next_run)
{
- int i;
- struct alarm_list *t;
+ struct rb_node *node = alarm_root.rb_node;
struct timeval tv;
- struct timeval cand = {
- .tv_sec = LONG_MAX,
- .tv_usec = LONG_MAX
- };
gettimeofday(&tv, NULL);
- for (i=0; i<ALARM_HASH_SIZE; i++) {
- if (!list_empty(&alarm_hash[i])) {
- t = list_entry(alarm_hash[i].next,
- struct alarm_list,
- head);
- if (timercmp(&t->tv, &cand, <)) {
- cand.tv_sec = t->tv.tv_sec;
- cand.tv_usec = t->tv.tv_usec;
- }
- }
+ node = rb_first(&alarm_root);
+ if (node) {
+ struct alarm_block *this;
+ this = container_of(node, struct alarm_block, node);
+ return calculate_next_run(&this->tv, &tv, next_run);
}
-
- return calculate_next_run(&cand, &tv, next_run);
-}
-
-static inline int
-tv_compare(struct alarm_list *a, struct timeval *cur, struct timeval *cand)
-{
- if (timercmp(&a->tv, cur, >)) {
- /* select the next alarm candidate */
- if (timercmp(&a->tv, cand, <)) {
- cand->tv_sec = a->tv.tv_sec;
- cand->tv_usec = a->tv.tv_usec;
- }
- return 1;
- }
- return 0;
+ return NULL;
}
struct timeval *
do_alarm_run(struct timeval *next_run)
{
- int i;
- struct alarm_list *t, *next, *prev;
+ struct rb_node *node = alarm_root.rb_node;
+ struct alarm_block *this, *tmp;
struct timeval tv;
- struct timeval cand = {
- .tv_sec = LONG_MAX,
- .tv_usec = LONG_MAX
- };
gettimeofday(&tv, NULL);
- for (i=0; i<ALARM_HASH_SIZE; i++) {
- list_for_each_entry_safe(t, next, &alarm_hash[i], head) {
- if (tv_compare(t, &tv, &cand))
- break;
-
- /* annotate previous alarm */
- prev = list_entry(next->head.prev,
- struct alarm_list,
- head);
-
- del_alarm(t);
- t->function(t, t->data);
-
- /* Special case: One deleted node is inserted
- * again in the same place */
- if (next->head.prev == &prev->head) {
- t = list_entry(next->head.prev,
- struct alarm_list,
- head);
- if (tv_compare(t, &tv, &cand))
- break;
- }
- }
- }
+ node = rb_first(&alarm_root);
+ while (node) {
+ this = container_of(node, struct alarm_block, node);
- return calculate_next_run(&cand, &tv, next_run);
-}
+ if (timercmp(&this->tv, &tv, >))
+ break;
-int init_alarm_hash(void)
-{
- int i;
+ node = rb_next(node);
- alarm_hash = malloc(sizeof(struct list_head) * ALARM_HASH_SIZE);
- if (alarm_hash == NULL)
- return -1;
-
- for (i=0; i<ALARM_HASH_SIZE; i++)
- INIT_LIST_HEAD(&alarm_hash[i]);
+ list_add(&this->list, &alarm_run_queue);
+ }
- return 0;
-}
+ list_for_each_entry_safe(this, tmp, &alarm_run_queue, list) {
+ list_del(&this->list);
+ rb_erase(&this->node, &alarm_root);
+ RB_CLEAR_NODE(&this->node);
+ this->function(this, this->data);
+ }
-void destroy_alarm_hash(void)
-{
- free(alarm_hash);
+ return get_next_alarm_run(next_run);
}
diff --git a/src/cache_timer.c b/src/cache_timer.c
index fe997ec..6619c2c 100644
--- a/src/cache_timer.c
+++ b/src/cache_timer.c
@@ -24,7 +24,7 @@
#include <stdio.h>
-static void timeout(struct alarm_list *a, void *data)
+static void timeout(struct alarm_block *a, void *data)
{
struct us_conntrack *u = data;
@@ -34,7 +34,7 @@ static void timeout(struct alarm_list *a, void *data)
static void timer_add(struct us_conntrack *u, void *data)
{
- struct alarm_list *alarm = data;
+ struct alarm_block *alarm = data;
init_alarm(alarm, u, timeout);
add_alarm(alarm, CONFIG(cache_timeout), 0);
@@ -42,20 +42,20 @@ static void timer_add(struct us_conntrack *u, void *data)
static void timer_update(struct us_conntrack *u, void *data)
{
- struct alarm_list *alarm = data;
+ struct alarm_block *alarm = data;
add_alarm(alarm, CONFIG(cache_timeout), 0);
}
static void timer_destroy(struct us_conntrack *u, void *data)
{
- struct alarm_list *alarm = data;
+ struct alarm_block *alarm = data;
del_alarm(alarm);
}
static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type)
{
struct timeval tv, tmp;
- struct alarm_list *alarm = data;
+ struct alarm_block *alarm = data;
if (type == NFCT_O_XML)
return 0;
@@ -69,7 +69,7 @@ static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type)
}
struct cache_feature timer_feature = {
- .size = sizeof(struct alarm_list),
+ .size = sizeof(struct alarm_block),
.add = timer_add,
.update = timer_update,
.destroy = timer_destroy,
diff --git a/src/rbtree.c b/src/rbtree.c
new file mode 100644
index 0000000..199e2bb
--- /dev/null
+++ b/src/rbtree.c
@@ -0,0 +1,389 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
+ (C) 2002 David Woodhouse <dwmw2@infradead.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/lib/rbtree.c
+*/
+
+#include "linux_rbtree.h"
+
+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *right = node->rb_right;
+ struct rb_node *parent = rb_parent(node);
+
+ if ((node->rb_right = right->rb_left))
+ rb_set_parent(right->rb_left, node);
+ right->rb_left = node;
+
+ rb_set_parent(right, parent);
+
+ if (parent)
+ {
+ if (node == parent->rb_left)
+ parent->rb_left = right;
+ else
+ parent->rb_right = right;
+ }
+ else
+ root->rb_node = right;
+ rb_set_parent(node, right);
+}
+
+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *left = node->rb_left;
+ struct rb_node *parent = rb_parent(node);
+
+ if ((node->rb_left = left->rb_right))
+ rb_set_parent(left->rb_right, node);
+ left->rb_right = node;
+
+ rb_set_parent(left, parent);
+
+ if (parent)
+ {
+ if (node == parent->rb_right)
+ parent->rb_right = left;
+ else
+ parent->rb_left = left;
+ }
+ else
+ root->rb_node = left;
+ rb_set_parent(node, left);
+}
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *parent, *gparent;
+
+ while ((parent = rb_parent(node)) && rb_is_red(parent))
+ {
+ gparent = rb_parent(parent);
+
+ if (parent == gparent->rb_left)
+ {
+ {
+ register struct rb_node *uncle = gparent->rb_right;
+ if (uncle && rb_is_red(uncle))
+ {
+ rb_set_black(uncle);
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->rb_right == node)
+ {
+ register struct rb_node *tmp;
+ __rb_rotate_left(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ __rb_rotate_right(gparent, root);
+ } else {
+ {
+ register struct rb_node *uncle = gparent->rb_left;
+ if (uncle && rb_is_red(uncle))
+ {
+ rb_set_black(uncle);
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->rb_left == node)
+ {
+ register struct rb_node *tmp;
+ __rb_rotate_right(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ __rb_rotate_left(gparent, root);
+ }
+ }
+
+ rb_set_black(root->rb_node);
+}
+
+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
+ struct rb_root *root)
+{
+ struct rb_node *other;
+
+ while ((!node || rb_is_black(node)) && node != root->rb_node)
+ {
+ if (parent->rb_left == node)
+ {
+ other = parent->rb_right;
+ if (rb_is_red(other))
+ {
+ rb_set_black(other);
+ rb_set_red(parent);
+ __rb_rotate_left(parent, root);
+ other = parent->rb_right;
+ }
+ if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+ (!other->rb_right || rb_is_black(other->rb_right)))
+ {
+ rb_set_red(other);
+ node = parent;
+ parent = rb_parent(node);
+ }
+ else
+ {
+ if (!other->rb_right || rb_is_black(other->rb_right))
+ {
+ struct rb_node *o_left;
+ if ((o_left = other->rb_left))
+ rb_set_black(o_left);
+ rb_set_red(other);
+ __rb_rotate_right(other, root);
+ other = parent->rb_right;
+ }
+ rb_set_color(other, rb_color(parent));
+ rb_set_black(parent);
+ if (other->rb_right)
+ rb_set_black(other->rb_right);
+ __rb_rotate_left(parent, root);
+ node = root->rb_node;
+ break;
+ }
+ }
+ else
+ {
+ other = parent->rb_left;
+ if (rb_is_red(other))
+ {
+ rb_set_black(other);
+ rb_set_red(parent);
+ __rb_rotate_right(parent, root);
+ other = parent->rb_left;
+ }
+ if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+ (!other->rb_right || rb_is_black(other->rb_right)))
+ {
+ rb_set_red(other);
+ node = parent;
+ parent = rb_parent(node);
+ }
+ else
+ {
+ if (!other->rb_left || rb_is_black(other->rb_left))
+ {
+ register struct rb_node *o_right;
+ if ((o_right = other->rb_right))
+ rb_set_black(o_right);
+ rb_set_red(other);
+ __rb_rotate_left(other, root);
+ other = parent->rb_left;
+ }
+ rb_set_color(other, rb_color(parent));
+ rb_set_black(parent);
+ if (other->rb_left)
+ rb_set_black(other->rb_left);
+ __rb_rotate_right(parent, root);
+ node = root->rb_node;
+ break;
+ }
+ }
+ }
+ if (node)
+ rb_set_black(node);
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *child, *parent;
+ int color;
+
+ if (!node->rb_left)
+ child = node->rb_right;
+ else if (!node->rb_right)
+ child = node->rb_left;
+ else
+ {
+ struct rb_node *old = node, *left;
+
+ node = node->rb_right;
+ while ((left = node->rb_left) != NULL)
+ node = left;
+ child = node->rb_right;
+ parent = rb_parent(node);
+ color = rb_color(node);
+
+ if (child)
+ rb_set_parent(child, parent);
+ if (parent == old) {
+ parent->rb_right = child;
+ parent = node;
+ } else
+ parent->rb_left = child;
+
+ node->rb_parent_color = old->rb_parent_color;
+ node->rb_right = old->rb_right;
+ node->rb_left = old->rb_left;
+
+ if (rb_parent(old))
+ {
+ if (rb_parent(old)->rb_left == old)
+ rb_parent(old)->rb_left = node;
+ else
+ rb_parent(old)->rb_right = node;
+ } else
+ root->rb_node = node;
+
+ rb_set_parent(old->rb_left, node);
+ if (old->rb_right)
+ rb_set_parent(old->rb_right, node);
+ goto color;
+ }
+
+ parent = rb_parent(node);
+ color = rb_color(node);
+
+ if (child)
+ rb_set_parent(child, parent);
+ if (parent)
+ {
+ if (parent->rb_left == node)
+ parent->rb_left = child;
+ else
+ parent->rb_right = child;
+ }
+ else
+ root->rb_node = child;
+
+ color:
+ if (color == RB_BLACK)
+ __rb_erase_color(child, parent, root);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_left)
+ n = n->rb_left;
+ return n;
+}
+
+struct rb_node *rb_last(struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_right)
+ n = n->rb_right;
+ return n;
+}
+
+struct rb_node *rb_next(struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a right-hand child, go down and then left as far
+ as we can. */
+ if (node->rb_right) {
+ node = node->rb_right;
+ while (node->rb_left)
+ node=node->rb_left;
+ return node;
+ }
+
+ /* No right-hand children. Everything down and left is
+ smaller than us, so any 'next' node must be in the general
+ direction of our parent. Go up the tree; any time the
+ ancestor is a right-hand child of its parent, keep going
+ up. First time it's a left-hand child of its parent, said
+ parent is our 'next' node. */
+ while ((parent = rb_parent(node)) && node == parent->rb_right)
+ node = parent;
+
+ return parent;
+}
+
+struct rb_node *rb_prev(struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a left-hand child, go down and then right as far
+ as we can. */
+ if (node->rb_left) {
+ node = node->rb_left;
+ while (node->rb_right)
+ node=node->rb_right;
+ return node;
+ }
+
+ /* No left-hand children. Go up till we find an ancestor which
+ is a right-hand child of its parent */
+ while ((parent = rb_parent(node)) && node == parent->rb_left)
+ node = parent;
+
+ return parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+ struct rb_root *root)
+{
+ struct rb_node *parent = rb_parent(victim);
+
+ /* Set the surrounding nodes to point to the replacement */
+ if (parent) {
+ if (victim == parent->rb_left)
+ parent->rb_left = new;
+ else
+ parent->rb_right = new;
+ } else {
+ root->rb_node = new;
+ }
+ if (victim->rb_left)
+ rb_set_parent(victim->rb_left, new);
+ if (victim->rb_right)
+ rb_set_parent(victim->rb_right, new);
+
+ /* Copy the pointers/colour from the victim to the replacement */
+ *new = *victim;
+}
diff --git a/src/run.c b/src/run.c
index 876e131..f5832bc 100644
--- a/src/run.c
+++ b/src/run.c
@@ -42,7 +42,6 @@ void killer(int foo)
ignore_pool_destroy(STATE(ignore_pool));
local_server_destroy(&STATE(local));
STATE(mode)->kill();
- destroy_alarm_hash();
unlink(CONFIG(lockfile));
dlog(LOG_NOTICE, "---- shutdown received ----");
close_log();
@@ -103,11 +102,6 @@ init(void)
STATE(mode) = &stats_mode;
}
- if (init_alarm_hash() == -1) {
- dlog(LOG_ERR, "can't initialize alarm hash");
- return -1;
- }
-
/* Initialization */
if (STATE(mode)->init() == -1) {
dlog(LOG_ERR, "initialization failed");
diff --git a/src/sync-alarm.c b/src/sync-alarm.c
index c7cecc8..4473af2 100644
--- a/src/sync-alarm.c
+++ b/src/sync-alarm.c
@@ -27,7 +27,7 @@
#include <stdlib.h>
#include <string.h>
-static void refresher(struct alarm_list *a, void *data)
+static void refresher(struct alarm_block *a, void *data)
{
size_t len;
struct nethdr *net;
@@ -46,7 +46,7 @@ static void refresher(struct alarm_list *a, void *data)
static void cache_alarm_add(struct us_conntrack *u, void *data)
{
- struct alarm_list *alarm = data;
+ struct alarm_block *alarm = data;
init_alarm(alarm, u, refresher);
add_alarm(alarm,
@@ -56,7 +56,7 @@ static void cache_alarm_add(struct us_conntrack *u, void *data)
static void cache_alarm_update(struct us_conntrack *u, void *data)
{
- struct alarm_list *alarm = data;
+ struct alarm_block *alarm = data;
add_alarm(alarm,
random() % CONFIG(refresh) + 1,
((random() % 5 + 1) * 200000) - 1);
@@ -64,12 +64,12 @@ static void cache_alarm_update(struct us_conntrack *u, void *data)
static void cache_alarm_destroy(struct us_conntrack *u, void *data)
{
- struct alarm_list *alarm = data;
+ struct alarm_block *alarm = data;
del_alarm(alarm);
}
static struct cache_extra cache_alarm_extra = {
- .size = sizeof(struct alarm_list),
+ .size = sizeof(struct alarm_block),
.add = cache_alarm_add,
.update = cache_alarm_update,
.destroy = cache_alarm_destroy
diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c
index 49c0b2c..cac25d0 100644
--- a/src/sync-ftfw.c
+++ b/src/sync-ftfw.c
@@ -83,9 +83,9 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to)
queue_add(tx_queue, &ack, NETHDR_ACK_SIZ);
}
-static struct alarm_list alive_alarm;
+static struct alarm_block alive_alarm;
-static void do_alive_alarm(struct alarm_list *a, void *data)
+static void do_alive_alarm(struct alarm_block *a, void *data)
{
tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0);