diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2009-01-17 18:03:50 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2009-01-17 18:03:50 +0100 |
commit | b1d00262f999a597fa24af3298195db9cf52b790 (patch) | |
tree | 1d4219c35ff62fa663339e0c6a514f954f60f8b4 /src | |
parent | 786f37040cdcb64b24eb0b437307ed5e208f717f (diff) | |
download | conntrack-tools-b1d00262f999a597fa24af3298195db9cf52b790.tar.gz conntrack-tools-b1d00262f999a597fa24af3298195db9cf52b790.zip |
sync: enqueue state updates to tx_queue
With this patch, all the states updates are enqueued in the
tx_queue. Thus, there's a single output path. This patch adds a
simple refcounting mechanism to note when an object is sitting in
the txqueue. This patch also removes the alarm that is required by
the ftfw approach.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/cache.c | 59 | ||||
-rw-r--r-- | src/sync-alarm.c | 75 | ||||
-rw-r--r-- | src/sync-ftfw.c | 70 | ||||
-rw-r--r-- | src/sync-mode.c | 23 | ||||
-rw-r--r-- | src/sync-notrack.c | 12 |
5 files changed, 147 insertions, 92 deletions
diff --git a/src/cache.c b/src/cache.c index c46498b..1e08a33 100644 --- a/src/cache.c +++ b/src/cache.c @@ -174,8 +174,6 @@ void cache_destroy(struct cache *c) free(c); } -static void __del_timeout(struct alarm_block *a, void *data); - struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) { struct cache_object *obj; @@ -187,7 +185,6 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) return NULL; } obj->cache = c; - init_alarm(&obj->alarm, obj, __del_timeout); if ((obj->ct = nfct_new()) == NULL) { free(obj); @@ -207,6 +204,30 @@ void cache_object_free(struct cache_object *obj) free(obj); } +int cache_object_put(struct cache_object *obj) +{ + if (--obj->refcnt == 0) { + cache_del(obj->cache, obj); + cache_object_free(obj); + return 1; + } + return 0; +} + +void cache_object_get(struct cache_object *obj) +{ + obj->refcnt++; +} + +void cache_object_set_status(struct cache_object *obj, int status) +{ + if (status == C_OBJ_DEAD) { + obj->cache->stats.del_ok++; + obj->cache->stats.active--; + } + obj->status = status; +} + static int __add(struct cache *c, struct cache_object *obj, int id) { int ret; @@ -227,6 +248,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->stats.active++; obj->status = C_OBJ_NEW; + obj->refcnt++; return 0; } @@ -292,7 +314,6 @@ void cache_del(struct cache *c, struct cache_object *obj) c->stats.del_ok++; c->stats.active--; } - del_alarm(&obj->alarm); __del(c, obj); } @@ -322,36 +343,6 @@ cache_update_force(struct cache *c, struct nf_conntrack *ct) return obj; } -static void __del_timeout(struct alarm_block *a, void *data) -{ - struct cache_object *obj = (struct cache_object *) data; - __del(obj->cache, obj); - cache_object_free(obj); -} - -int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout) -{ - if (timeout <= 0) { - cache_del(c, obj); - cache_object_free(obj); - return 1; - } - if (obj->status != C_OBJ_DEAD) { - obj->status = C_OBJ_DEAD; - add_alarm(&obj->alarm, timeout, 0); - /* - * increase stats even if this entry was not really - * removed yet. We do not want to make people think - * that the replication protocol does not work - * properly. - */ - c->stats.del_ok++; - c->stats.active--; - return 1; - } - return 0; -} - struct cache_object * cache_find(struct cache *c, struct nf_conntrack *ct, int *id) { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 34937fe..a2f17ac 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -21,14 +21,21 @@ #include "network.h" #include "alarm.h" #include "cache.h" +#include "queue.h" #include "debug.h" #include <stdlib.h> #include <string.h> +struct cache_alarm { + struct queue_node qnode; + struct alarm_block alarm; +}; + +static void alarm_enqueue(struct cache_object *obj, int query); + static void refresher(struct alarm_block *a, void *data) { - struct nethdr *net; struct cache_object *obj = data; debug_ct(obj->ct, "persistence update"); @@ -37,36 +44,37 @@ static void refresher(struct alarm_block *a, void *data) random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - net = BUILD_NETMSG(obj->ct, NET_T_STATE_UPD); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + alarm_enqueue(obj, NET_T_STATE_UPD); } static void cache_alarm_add(struct cache_object *obj, void *data) { - struct alarm_block *a = data; + struct cache_alarm *ca = data; - init_alarm(a, obj, refresher); - add_alarm(a, + queue_node_init(&ca->qnode, Q_ELEM_OBJ); + init_alarm(&ca->alarm, obj, refresher); + add_alarm(&ca->alarm, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } static void cache_alarm_update(struct cache_object *obj, void *data) { - struct alarm_block *a = data; - add_alarm(a, + struct cache_alarm *ca = data; + add_alarm(&ca->alarm, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } static void cache_alarm_destroy(struct cache_object *obj, void *data) { - struct alarm_block *a = data; - del_alarm(a); + struct cache_alarm *ca = data; + queue_del(&ca->qnode); + del_alarm(&ca->alarm); } static struct cache_extra cache_alarm_extra = { - .size = sizeof(struct alarm_block), + .size = sizeof(struct cache_alarm), .add = cache_alarm_add, .update = cache_alarm_update, .destroy = cache_alarm_destroy @@ -102,9 +110,54 @@ static int alarm_recv(const struct nethdr *net) return 0; } +static void alarm_enqueue(struct cache_object *obj, int query) +{ + struct cache_alarm *ca = cache_get_extra(STATE_SYNC(internal), obj); + if (queue_add(STATE_SYNC(tx_queue), &ca->qnode)) + cache_object_get(obj); +} + +static int tx_queue_xmit(struct queue_node *n, const void *data) +{ + struct nethdr *net; + + queue_del(n); + + switch(n->type) { + case Q_ELEM_CTL: + net = queue_node_data(n); + nethdr_set_ctl(net); + HDR_HOST2NETWORK(net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + queue_object_free((struct queue_object *)n); + break; + case Q_ELEM_OBJ: { + struct cache_alarm *ca; + struct cache_object *obj; + int type; + + ca = (struct cache_alarm *)n; + obj = cache_data_get_object(STATE_SYNC(internal), ca); + type = object_status_to_network_type(obj->status); + net = BUILD_NETMSG(obj->ct, type); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + cache_object_put(obj); + break; + } + } + return 0; +} + +static void alarm_xmit(void) +{ + queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); +} + struct sync_mode sync_alarm = { .internal_cache_flags = LIFETIME, .external_cache_flags = TIMER | LIFETIME, .internal_cache_extra = &cache_alarm_extra, .recv = alarm_recv, + .enqueue = alarm_enqueue, + .xmit = alarm_xmit, }; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index d544a7b..a287ecd 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -168,11 +168,13 @@ static int do_cache_to_tx(void *data1, void *data2) struct cache_object *obj = data2; struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); - if (queue_in(rs_queue, &cn->qnode)) + if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); - - queue_add(STATE_SYNC(tx_queue), &cn->qnode); - + queue_add(STATE_SYNC(tx_queue), &cn->qnode); + } else { + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); + } return 0; } @@ -278,16 +280,15 @@ static int rs_queue_empty(struct queue_node *n, const void *data) { const struct nethdr_ack *h = data; - if (h == NULL) { - dp("inconditional remove from queue (seq=%u)\n", net->seq); - queue_del(n); - return 0; - } - switch(n->type) { case Q_ELEM_CTL: { struct nethdr_ack *net = queue_node_data(n); + if (h == NULL) { + queue_del(n); + queue_object_free((struct queue_object *)n); + return 0; + } if (before(net->seq, h->from)) return 0; /* continue */ else if (after(net->seq, h->to)) @@ -300,8 +301,15 @@ static int rs_queue_empty(struct queue_node *n, const void *data) } case Q_ELEM_OBJ: { struct cache_ftfw *cn; + struct cache_object *obj; cn = (struct cache_ftfw *) n; + if (h == NULL) { + queue_del(n); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + cache_object_put(obj); + return 0; + } if (before(cn->seq, h->from)) return 0; else if (after(cn->seq, h->to)) @@ -309,6 +317,8 @@ static int rs_queue_empty(struct queue_node *n, const void *data) dp("queue: deleting from queue (seq=%u)\n", cn->seq); queue_del(n); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + cache_object_put(obj); break; } } @@ -441,28 +451,6 @@ out: return ret; } -static void ftfw_send(struct nethdr *net, struct cache_object *obj) -{ - struct cache_ftfw *cn; - - switch(net->type) { - case NET_T_STATE_NEW: - case NET_T_STATE_UPD: - case NET_T_STATE_DEL: - cn = (struct cache_ftfw *) - cache_get_extra(STATE_SYNC(internal), obj); - - if (queue_in(rs_queue, &cn->qnode)) - queue_del(&cn->qnode); - - nethdr_set_hello(net); - - cn->seq = ntohl(net->seq); - queue_add(rs_queue, &cn->qnode); - break; - } -} - static int tx_queue_xmit(struct queue_node *n, const void *data) { queue_del(n); @@ -511,7 +499,9 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) ntohl(net->seq), net->flags, ntohs(net->len)); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - ftfw_send(net, obj); + cn->seq = ntohl(net->seq); + queue_add(rs_queue, &cn->qnode); + /* we release the object once we get the acknowlegment */ break; } } @@ -527,6 +517,18 @@ static void ftfw_xmit(void) queue_len(tx_queue), queue_len(rs_queue)); } +static void ftfw_enqueue(struct cache_object *obj, int type) +{ + struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); + if (queue_in(rs_queue, &cn->qnode)) { + queue_del(&cn->qnode); + queue_add(STATE_SYNC(tx_queue), &cn->qnode); + } else { + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); + } +} + struct sync_mode sync_ftfw = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, @@ -535,6 +537,6 @@ struct sync_mode sync_ftfw = { .kill = ftfw_kill, .local = ftfw_local, .recv = ftfw_recv, - .send = ftfw_send, + .enqueue = ftfw_enqueue, .xmit = ftfw_xmit, }; diff --git a/src/sync-mode.c b/src/sync-mode.c index 5ae9062..00e2f7b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -442,14 +442,7 @@ static void dump_sync(struct nf_conntrack *ct) static void mcast_send_sync(struct cache_object *obj, int query) { - struct nethdr *net; - - net = BUILD_NETMSG(obj->ct, query); - - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, obj); - - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + STATE_SYNC(sync)->enqueue(obj, query); } static int purge_step(void *data1, void *data2) @@ -461,8 +454,11 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { debug_ct(obj->ct, "overrun purge resync"); - mcast_send_sync(obj, NET_T_STATE_DEL); - cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_object_put(obj); + } } return 0; @@ -552,8 +548,11 @@ static int event_destroy_sync(struct nf_conntrack *ct) debug_ct(ct, "can't destroy"); return 0; } - mcast_send_sync(obj, NET_T_STATE_DEL); - cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_object_put(obj); + } debug_ct(ct, "internal destroy"); return 1; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 4ded298..3b547ee 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -71,7 +71,8 @@ static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); - queue_add(STATE_SYNC(tx_queue), &cn->qnode); + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); return 0; } @@ -152,6 +153,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); queue_del(n); + cache_object_put(obj); break; } } @@ -163,11 +165,19 @@ static void notrack_xmit(void) queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); } +static void notrack_enqueue(struct cache_object *obj, int query) +{ + struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); +} + struct sync_mode sync_notrack = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, .internal_cache_extra = &cache_notrack_extra, .local = notrack_local, .recv = notrack_recv, + .enqueue = notrack_enqueue, .xmit = notrack_xmit, }; |