]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft: Eliminate table list from cache
authorPhil Sutter <phil@nwl.cc>
Thu, 30 Jul 2020 09:54:36 +0000 (11:54 +0200)
committerPhil Sutter <phil@nwl.cc>
Fri, 31 Jul 2020 11:37:20 +0000 (13:37 +0200)
The full list of tables in kernel is not relevant, only those used by
iptables-nft and for those, knowing if they exist or not is sufficient.
For holding that information, the already existing 'table' array in
nft_cache suits well.

Consequently, nft_table_find() merely checks if the new 'exists' boolean
is true or not and nft_for_each_table() iterates over the builtin_table
array in nft_handle, additionally checking the boolean in cache for
whether to skip the entry or not.

Signed-off-by: Phil Sutter <phil@nwl.cc>
iptables/nft-cache.c
iptables/nft-cache.h
iptables/nft.c
iptables/nft.h

index bf1fb346f28fdc2303c0258938d09a6f28dbee5a..c6baf090ae85f3d791ac9ca746d9e3a7b09731c9 100644 (file)
@@ -107,59 +107,30 @@ static void mnl_genid_get(struct nft_handle *h, uint32_t *genid)
                      "Could not fetch rule set generation id: %s\n", nft_strerror(errno));
 }
 
-static struct nft_table *nft_table_alloc(void)
-{
-       struct nftnl_table *nftnl;
-       struct nft_table *table;
-
-       table = malloc(sizeof(struct nft_table));
-       if (!table)
-               return NULL;
-
-       nftnl = nftnl_table_alloc();
-       if (!nftnl) {
-               free(table);
-               return NULL;
-       }
-       table->nftnl = nftnl;
-
-       return table;
-}
-
-static void nft_table_free(struct nft_table *table)
+static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
 {
-       nftnl_table_free(table->nftnl);
-       free(table);
-}
+       struct nftnl_table *nftnl = nftnl_table_alloc();
+       const struct builtin_table *t;
+       struct nft_handle *h = data;
+       const char *name;
 
-static void nft_table_list_free(struct list_head *table_list)
-{
-       struct nft_table *table, *next;
+       if (!nftnl)
+               return MNL_CB_OK;
 
-       list_for_each_entry_safe(table, next, table_list, list) {
-               list_del(&table->list);
-               nft_table_free(table);
-       }
-}
+       if (nftnl_table_nlmsg_parse(nlh, nftnl) < 0)
+               goto out;
 
-static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
-{
-       struct list_head *list = data;
-       struct nft_table *t;
+       name = nftnl_table_get_str(nftnl, NFTNL_TABLE_NAME);
+       if (!name)
+               goto out;
 
-       t = nft_table_alloc();
+       t = nft_table_builtin_find(h, name);
        if (!t)
-               goto err;
-
-       if (nftnl_table_nlmsg_parse(nlh, t->nftnl) < 0)
                goto out;
 
-       list_add_tail(&t->list, list);
-
-       return MNL_CB_OK;
+       h->cache->table[t->type].exists = true;
 out:
-       nft_table_free(t);
-err:
+       nftnl_table_free(nftnl);
        return MNL_CB_OK;
 }
 
@@ -169,13 +140,10 @@ static int fetch_table_cache(struct nft_handle *h)
        char buf[16536];
        int i, ret;
 
-       if (!list_empty(&h->cache->tables))
-               return 0;
-
        nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
                                        NLM_F_DUMP, h->seq);
 
-       ret = mnl_talk(h, nlh, nftnl_table_list_cb, &h->cache->tables);
+       ret = mnl_talk(h, nlh, nftnl_table_list_cb, h);
        if (ret < 0 && errno == EINTR)
                assert(nft_restart(h) >= 0);
 
@@ -635,9 +603,9 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
                        nftnl_set_list_free(c->table[i].sets);
                        c->table[i].sets = NULL;
                }
+
+               c->table[i].exists = false;
        }
-       if (!list_empty(&c->tables))
-               nft_table_list_free(&c->tables);
 
        return 1;
 }
@@ -710,11 +678,6 @@ void nft_release_cache(struct nft_handle *h)
        }
 }
 
-struct list_head *nft_table_list_get(struct nft_handle *h)
-{
-       return &h->cache->tables;
-}
-
 struct nftnl_set_list *
 nft_set_list_get(struct nft_handle *h, const char *table, const char *set)
 {
index aeab4bdef904dc72aa508a4ff98fd8404aa706d0..76f9fbb6c8cccdc3e9f23533461b3e3df8334bb5 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _NFT_CACHE_H_
 #define _NFT_CACHE_H_
 
-#include <libiptc/linux_list.h>
-
 struct nft_handle;
 struct nft_cmd;
 
@@ -19,12 +17,5 @@ struct nftnl_chain_list *
 nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain);
 struct nftnl_set_list *
 nft_set_list_get(struct nft_handle *h, const char *table, const char *set);
-struct list_head *nft_table_list_get(struct nft_handle *h);
-
-struct nft_table {
-       struct list_head        list;
-       struct nftnl_table      *nftnl;
-};
-
 
 #endif /* _NFT_CACHE_H_ */
index 634d02fed25b1925f3fc20a8aff4d3f08e319950..76fd7edd11177647b7d22ee06d81c6535e43dd28 100644 (file)
@@ -842,8 +842,6 @@ int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
        INIT_LIST_HEAD(&h->obj_list);
        INIT_LIST_HEAD(&h->err_list);
        INIT_LIST_HEAD(&h->cmd_list);
-       INIT_LIST_HEAD(&h->__cache[0].tables);
-       INIT_LIST_HEAD(&h->__cache[1].tables);
        INIT_LIST_HEAD(&h->cache_req.chain_list);
 
        return 0;
@@ -1943,39 +1941,26 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
 
 bool nft_table_find(struct nft_handle *h, const char *tablename)
 {
-       struct list_head *list;
-       struct nft_table *t;
-       bool ret = false;
-
-       list = nft_table_list_get(h);
-
-       list_for_each_entry(t, list, list) {
-               const char *this_tablename =
-                       nftnl_table_get(t->nftnl, NFTNL_TABLE_NAME);
-
-               if (strcmp(tablename, this_tablename) == 0) {
-                       ret = true;
-                       break;
-               }
-       }
+       const struct builtin_table *t;
 
-       return ret;
+       t = nft_table_builtin_find(h, tablename);
+       return t ? h->cache->table[t->type].exists : false;
 }
 
 int nft_for_each_table(struct nft_handle *h,
                       int (*func)(struct nft_handle *h, const char *tablename, void *data),
                       void *data)
 {
-       struct list_head *list;
-       struct nft_table *t;
+       int i;
 
-       list = nft_table_list_get(h);
+       for (i = 0; i < NFT_TABLE_MAX; i++) {
+               if (h->tables[i].name == NULL)
+                       continue;
 
-       list_for_each_entry(t, list, list) {
-               const char *tablename =
-                       nftnl_table_get(t->nftnl, NFTNL_TABLE_NAME);
+               if (!h->cache->table[h->tables[i].type].exists)
+                       continue;
 
-               func(h, tablename, data);
+               func(h, h->tables[i].name, data);
        }
 
        return 0;
@@ -2013,26 +1998,16 @@ static int __nft_table_flush(struct nft_handle *h, const char *table, bool exist
 
 int nft_table_flush(struct nft_handle *h, const char *table)
 {
-       struct list_head *list;
-       struct nft_table *t;
-       bool exists = false;
+       const struct builtin_table *t;
        int ret = 0;
 
        nft_fn = nft_table_flush;
 
-       list = nft_table_list_get(h);
-
-       list_for_each_entry(t, list, list) {
-               const char *table_name =
-                       nftnl_table_get_str(t->nftnl, NFTNL_TABLE_NAME);
-
-               if (strcmp(table_name, table) == 0) {
-                       exists = true;
-                       break;
-               }
-       }
+       t = nft_table_builtin_find(h, table);
+       if (!t)
+               return 0;
 
-       ret = __nft_table_flush(h, table, exists);
+       ret = __nft_table_flush(h, table, h->cache->table[t->type].exists);
 
        /* the core expects 1 for success and 0 for error */
        return ret == 0 ? 1 : 0;
index b2175958bfcd69357c56ce0754e93dc0cd82a364..f38f5812be7719e2db41a77b906a2b898d3c3e54 100644 (file)
@@ -38,11 +38,11 @@ enum nft_cache_level {
 };
 
 struct nft_cache {
-       struct list_head                tables;
        struct {
                struct nftnl_chain_list *chains;
                struct nftnl_set_list   *sets;
                bool                    initialized;
+               bool                    exists;
        } table[NFT_TABLE_MAX];
 };