summaryrefslogtreecommitdiffstats
path: root/src/cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cache.c')
-rw-r--r--src/cache.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/cache.c b/src/cache.c
index 7797ff6b..ed260900 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -12,6 +12,9 @@
#include <erec.h>
#include <utils.h>
#include <cache.h>
+#include <netlink.h>
+#include <mnl.h>
+#include <libnftnl/chain.h>
static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
{
@@ -164,3 +167,92 @@ unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
return flags;
}
+
+struct chain_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
+{
+ struct chain_cache_dump_ctx *ctx = arg;
+ const char *chain_name, *table_name;
+ uint32_t hash, family;
+ struct chain *chain;
+
+ table_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE);
+ chain_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME);
+ family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
+
+ if (strcmp(table_name, ctx->table->handle.table.name) ||
+ family != ctx->table->handle.family)
+ return 0;
+
+ hash = djb_hash(chain_name) % NFT_CACHE_HSIZE;
+ chain = netlink_delinearize_chain(ctx->nlctx, nlc);
+
+ if (chain->flags & CHAIN_F_BINDING) {
+ list_add_tail(&chain->list, &ctx->table->chain_bindings);
+ } else {
+ list_add_tail(&chain->hlist, &ctx->table->chain_htable[hash]);
+ list_add_tail(&chain->list, &ctx->table->chains);
+ }
+
+ nftnl_chain_list_del(nlc);
+ nftnl_chain_free(nlc);
+
+ return 0;
+}
+
+int chain_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_chain_list *chain_list)
+{
+ struct chain_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+ nftnl_chain_list_foreach(chain_list, chain_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+struct nftnl_chain_list *chain_cache_dump(struct netlink_ctx *ctx, int *err)
+{
+ struct nftnl_chain_list *chain_list;
+
+ chain_list = mnl_nft_chain_dump(ctx, AF_UNSPEC);
+ if (chain_list == NULL) {
+ if (errno == EINTR) {
+ *err = -1;
+ return NULL;
+ }
+ *err = 0;
+ return NULL;
+ }
+
+ return chain_list;
+}
+
+void chain_cache_add(struct chain *chain, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(chain->handle.chain.name) % NFT_CACHE_HSIZE;
+ list_add_tail(&chain->hlist, &table->chain_htable[hash]);
+ list_add_tail(&chain->list, &table->chains);
+}
+
+struct chain *chain_cache_find(const struct table *table,
+ const struct handle *handle)
+{
+ struct chain *chain;
+ uint32_t hash;
+
+ hash = djb_hash(handle->chain.name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(chain, &table->chain_htable[hash], hlist) {
+ if (!strcmp(chain->handle.chain.name, handle->chain.name))
+ return chain;
+ }
+
+ return NULL;
+}