#include #define HASH_FUNCTION(keyptr, keylen, hashv) HASH_FUNCTION_OVERWRITE(keyptr, keylen, &hashv) #define HASH_KEYCMP(a, b, len) HASH_KEYCMP_OVERWRITE(a, b, len) #include "session_table.h" struct session_table { struct session *root; session_free_cb free_cb; void *arg; uint64_t count; struct list_head lru_queue; }; /****************************************************************************** * Private API ******************************************************************************/ static void HASH_FUNCTION_OVERWRITE(const struct tuple6 *tuple, unsigned int keylen, uint32_t *hashv) { *hashv = tuple6_hash(tuple); } static int HASH_KEYCMP_OVERWRITE(const void *key_a, const void *key_b, size_t len) { struct tuple6 *tuple_a = (struct tuple6 *)key_a; struct tuple6 *tuple_b = (struct tuple6 *)key_b; if (tuple6_cmp(tuple_a, tuple_b) == 0) { return 0; } struct tuple6 reversed; tuple6_reverse(tuple_b, &reversed); if (tuple6_cmp(tuple_a, &reversed) == 0) { return 0; } return -1; } /****************************************************************************** * Public API ******************************************************************************/ struct session_table *session_table_new() { struct session_table *table = (struct session_table *)calloc(1, sizeof(struct session_table)); if (table == NULL) { return NULL; } table->count = 0; INIT_LIST_HEAD(&table->lru_queue); return table; } void session_table_free(struct session_table *table) { if (table) { struct session *node = NULL; struct session *tmp = NULL; HASH_ITER(hh, table->root, node, tmp) { list_del(&node->lru); HASH_DELETE(hh, table->root, node); if (table->free_cb && node) { table->free_cb(node, table->arg); } } table->count--; free(table); table = NULL; } } uint64_t session_table_get_count(struct session_table *table) { if (table == NULL) { return 0; } return table->count; } void session_table_set_freecb(struct session_table *table, session_free_cb free_cb, void *arg) { if (table) { table->free_cb = free_cb; table->arg = arg; } } int session_table_add(struct session_table *table, const struct tuple6 *tuple, struct session *sess) { if (table == NULL || sess == NULL) { return -1; } if (session_table_find_tuple(table, tuple)) { return -1; } list_add_tail(&sess->lru, &table->lru_queue); HASH_ADD(hh, table->root, tuple, sizeof(sess->tuple), sess); table->count++; return 0; } void session_table_del(struct session_table *table, const struct tuple6 *tuple) { if (table == NULL) { return; } struct session *sess = session_table_find_tuple(table, tuple); if (sess == NULL) { return; } list_del(&sess->lru); HASH_DELETE(hh, table->root, sess); if (table->free_cb && sess) { table->free_cb(sess, table->arg); } table->count--; } struct session *session_table_find_tuple(struct session_table *table, const struct tuple6 *tuple) { if (table == NULL) { return NULL; } struct session *sess = NULL; HASH_FIND(hh, table->root, tuple, sizeof(struct tuple6), sess); if (sess == NULL) { struct tuple6 out; memset(&out, 0, sizeof(struct tuple6)); tuple6_reverse(tuple, &out); HASH_FIND(hh, table->root, &out, sizeof(struct tuple6), sess); } if (sess) { list_del(&sess->lru); list_add_tail(&sess->lru, &table->lru_queue); } return sess; } struct session *session_table_find_lru(struct session_table *table) { if (table == NULL) { return NULL; } if (list_empty(&table->lru_queue)) { return NULL; } else { return list_first_entry(&table->lru_queue, struct session, lru); } }