summaryrefslogtreecommitdiffstats
path: root/src/cache.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2012-01-04 14:28:50 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2012-01-10 01:54:26 +0100
commit65be3d49b0f4350a227dedd70ac17c7c9cf6274e (patch)
treeebe1954323cc40b05d1772f46b5a54d4948c2918 /src/cache.c
parent1f29809eac0b9d8c711c97e8fcec6833fcd30248 (diff)
conntrackd: generalize caching infrastructure
This patch generalizes the caching infrastructure to store different object types. This patch is the first in the series to prepare support for the synchronization of expectations. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/cache.c')
-rw-r--r--src/cache.c154
1 files changed, 65 insertions, 89 deletions
diff --git a/src/cache.c b/src/cache.c
index f411121..efdab0e 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -1,5 +1,6 @@
/*
- * (C) 2006-2009 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2006-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2011 by Vyatta Inc. <http://www.vyatta.com>
*
* 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
@@ -28,80 +29,14 @@
#include <string.h>
#include <time.h>
-static uint32_t
-__hash4(const struct nf_conntrack *ct, const struct hashtable *table)
-{
- uint32_t a[4] = {
- [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC),
- [1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST),
- [2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 |
- nfct_get_attr_u8(ct, ATTR_L4PROTO),
- [3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 |
- nfct_get_attr_u16(ct, ATTR_PORT_DST),
- };
-
- /*
- * Instead of returning hash % table->hashsize (implying a divide)
- * we return the high 32 bits of the (hash * table->hashsize) that will
- * give results between [0 and hashsize-1] and same hash distribution,
- * but using a multiply, less expensive than a divide. See:
- * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html
- */
- return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32;
-}
-
-static uint32_t
-__hash6(const struct nf_conntrack *ct, const struct hashtable *table)
-{
- uint32_t a[10];
-
- memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4);
- memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4);
- a[8] = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16 |
- nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
- a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 |
- nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
-
- return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32;
-}
-
-static uint32_t hash(const void *data, const struct hashtable *table)
-{
- int ret = 0;
- const struct nf_conntrack *ct = data;
-
- switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) {
- case AF_INET:
- ret = __hash4(ct, table);
- break;
- case AF_INET6:
- ret = __hash6(ct, table);
- break;
- default:
- dlog(LOG_ERR, "unknown layer 3 proto in hash");
- break;
- }
-
- return ret;
-}
-
-static int compare(const void *data1, const void *data2)
-{
- const struct cache_object *obj = data1;
- const struct nf_conntrack *ct = data2;
-
- return nfct_cmp(obj->ct, ct, NFCT_CMP_ORIG) &&
- nfct_get_attr_u32(obj->ct, ATTR_ID) ==
- nfct_get_attr_u32(ct, ATTR_ID);
-}
-
struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = {
[TIMER_FEATURE] = &timer_feature,
};
-struct cache *cache_create(const char *name,
+struct cache *cache_create(const char *name, enum cache_type type,
unsigned int features,
- struct cache_extra *extra)
+ struct cache_extra *extra,
+ struct cache_ops *ops)
{
size_t size = sizeof(struct cache_object);
int i, j = 0;
@@ -110,12 +45,16 @@ struct cache *cache_create(const char *name,
unsigned int feature_offset[CACHE_MAX_FEATURE] = {};
unsigned int feature_type[CACHE_MAX_FEATURE] = {};
+ if (type == CACHE_T_NONE || type >= CACHE_T_MAX)
+ return NULL;
+
c = malloc(sizeof(struct cache));
if (!c)
return NULL;
memset(c, 0, sizeof(struct cache));
strcpy(c->name, name);
+ c->type = type;
for (i = 0; i < CACHE_MAX_FEATURE; i++) {
if ((1 << i) & features) {
@@ -150,11 +89,19 @@ struct cache *cache_create(const char *name,
}
memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j);
+ if (!ops || !ops->hash || !ops->cmp ||
+ !ops->alloc || !ops->copy || !ops->free) {
+ free(c->feature_offset);
+ free(c->features);
+ free(c);
+ return NULL;
+ }
+ c->ops = ops;
+
c->h = hashtable_create(CONFIG(hashsize),
CONFIG(limit),
- hash,
- compare);
-
+ c->ops->hash,
+ c->ops->cmp);
if (!c->h) {
free(c->features);
free(c->feature_offset);
@@ -175,7 +122,7 @@ void cache_destroy(struct cache *c)
free(c);
}
-struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct)
+struct cache_object *cache_object_new(struct cache *c, void *ptr)
{
struct cache_object *obj;
@@ -187,13 +134,14 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct)
}
obj->cache = c;
- if ((obj->ct = nfct_new()) == NULL) {
+ obj->ptr = c->ops->alloc();
+ if (obj->ptr == NULL) {
free(obj);
errno = ENOMEM;
c->stats.add_fail_enomem++;
return NULL;
}
- nfct_copy(obj->ct, ct, NFCT_CP_OVERRIDE);
+ c->ops->copy(obj->ptr, ptr, NFCT_CP_OVERRIDE);
obj->status = C_OBJ_NONE;
c->stats.objects++;
@@ -203,7 +151,8 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct)
void cache_object_free(struct cache_object *obj)
{
obj->cache->stats.objects--;
- nfct_destroy(obj->ct);
+ obj->cache->ops->free(obj->ptr);
+
free(obj);
}
@@ -271,13 +220,12 @@ int cache_add(struct cache *c, struct cache_object *obj, int id)
return 0;
}
-void cache_update(struct cache *c, struct cache_object *obj, int id,
- struct nf_conntrack *ct)
+void cache_update(struct cache *c, struct cache_object *obj, int id, void *ptr)
{
char *data = obj->data;
unsigned int i;
- nfct_copy(obj->ct, ct, NFCT_CP_META);
+ c->ops->copy(obj->ptr, ptr, NFCT_CP_META);
for (i = 0; i < c->num_features; i++) {
c->features[i]->update(obj, data);
@@ -322,23 +270,22 @@ void cache_del(struct cache *c, struct cache_object *obj)
__del(c, obj);
}
-struct cache_object *
-cache_update_force(struct cache *c, struct nf_conntrack *ct)
+struct cache_object *cache_update_force(struct cache *c, void *ptr)
{
struct cache_object *obj;
int id;
- obj = cache_find(c, ct, &id);
+ obj = cache_find(c, ptr, &id);
if (obj) {
if (obj->status != C_OBJ_DEAD) {
- cache_update(c, obj, id, ct);
+ cache_update(c, obj, id, ptr);
return obj;
} else {
cache_del(c, obj);
cache_object_free(obj);
}
}
- obj = cache_object_new(c, ct);
+ obj = cache_object_new(c, ptr);
if (obj == NULL)
return NULL;
@@ -350,11 +297,10 @@ cache_update_force(struct cache *c, struct nf_conntrack *ct)
return obj;
}
-struct cache_object *
-cache_find(struct cache *c, struct nf_conntrack *ct, int *id)
+struct cache_object *cache_find(struct cache *c, void *ptr, int *id)
{
- *id = hashtable_hash(c->h, ct);
- return ((struct cache_object *) hashtable_find(c->h, ct, *id));
+ *id = hashtable_hash(c->h, ptr);
+ return ((struct cache_object *) hashtable_find(c->h, ptr, *id));
}
struct cache_object *cache_data_get_object(struct cache *c, void *data)
@@ -432,3 +378,33 @@ void cache_iterate_limit(struct cache *c, void *data,
{
hashtable_iterate_limit(c->h, data, from, steps, iterate);
}
+
+void cache_dump(struct cache *c, int fd, int type)
+{
+ struct __dump_container tmp = {
+ .fd = fd,
+ .type = type
+ };
+ hashtable_iterate(c->h, (void *) &tmp, c->ops->dump_step);
+}
+
+int cache_commit(struct cache *c, struct nfct_handle *h, int clientfd)
+{
+ return c->ops->commit(c, h, clientfd);
+}
+
+static int do_flush(void *data, void *n)
+{
+ struct cache *c = data;
+ struct cache_object *obj = n;
+
+ cache_del(c, obj);
+ cache_object_free(obj);
+ return 0;
+}
+
+void cache_flush(struct cache *c)
+{
+ hashtable_iterate(c->h, c, do_flush);
+ c->stats.flush++;
+}