summaryrefslogtreecommitdiff
path: root/src/cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cache.c')
-rw-r--r--src/cache.c163
1 files changed, 67 insertions, 96 deletions
diff --git a/src/cache.c b/src/cache.c
index 74c5c4b..7c41e54 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;
}
- memcpy(obj->ct, ct, nfct_sizeof(ct));
+ 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,21 +297,15 @@ 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)
+void *cache_get_extra(struct cache_object *obj)
{
- return (struct cache_object *)((char*)data - c->extra_offset);
-}
-
-void *cache_get_extra(struct cache *c, void *data)
-{
- return (char*)data + c->extra_offset;
+ return (char*)obj + obj->cache->extra_offset;
}
void cache_stats(const struct cache *c, int fd)
@@ -432,3 +373,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++;
+}