Accept a builtin_table pointer in __nft_build_cache() and pass it along
when fetching chains and rules to operate on that table only (unless the
pointer is NULL).

Make use of it in nft_chain_list_get() since that accepts a table name
and performs a builtin table lookup internally already.

Signed-off-by: Phil Sutter <p...@nwl.cc>
---
 iptables/nft-cache.c | 82 ++++++++++++++++++++++++++++++--------------
 1 file changed, 57 insertions(+), 25 deletions(-)

diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
index afb2126b51495..822d6f20cf51c 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -11,6 +11,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <string.h>
 #include <xtables.h>
 
 #include <linux/netfilter/nf_tables.h>
@@ -105,13 +106,19 @@ static int fetch_table_cache(struct nft_handle *h)
        return 1;
 }
 
+struct nftnl_chain_list_cb_data {
+       struct nft_handle *h;
+       const struct builtin_table *t;
+};
+
 static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
 {
-       struct nft_handle *h = data;
-       const struct builtin_table *t;
+       struct nftnl_chain_list_cb_data *d = data;
+       const struct builtin_table *t = d->t;
        struct nftnl_chain_list *list;
+       struct nft_handle *h = d->h;
+       const char *tname, *cname;
        struct nftnl_chain *c;
-       const char *cname;
 
        c = nftnl_chain_alloc();
        if (c == NULL)
@@ -120,10 +127,15 @@ static int nftnl_chain_list_cb(const struct nlmsghdr 
*nlh, void *data)
        if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
                goto out;
 
-       t = nft_table_builtin_find(h,
-                       nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
-       if (!t)
+       tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
+
+       if (!t) {
+               t = nft_table_builtin_find(h, tname);
+               if (!t)
+                       goto out;
+       } else if (strcmp(t->name, tname)) {
                goto out;
+       }
 
        list = h->cache->table[t->type].chains;
        cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
@@ -140,30 +152,41 @@ err:
        return MNL_CB_OK;
 }
 
-static int fetch_chain_cache(struct nft_handle *h)
+static int fetch_chain_cache(struct nft_handle *h,
+                            const struct builtin_table *t)
 {
+       struct nftnl_chain_list_cb_data d = {
+               .h = h,
+               .t = t,
+       };
        char buf[16536];
        struct nlmsghdr *nlh;
        int i, ret;
 
-       for (i = 0; i < NFT_TABLE_MAX; i++) {
-               enum nft_table_type type = h->tables[i].type;
+       if (!t) {
+               for (i = 0; i < NFT_TABLE_MAX; i++) {
+                       enum nft_table_type type = h->tables[i].type;
 
-               if (!h->tables[i].name)
-                       continue;
+                       if (!h->tables[i].name)
+                               continue;
 
-               if (h->cache->table[type].chains)
-                       continue;
+                       if (h->cache->table[type].chains)
+                               continue;
 
-               h->cache->table[type].chains = nftnl_chain_list_alloc();
-               if (!h->cache->table[type].chains)
+                       h->cache->table[type].chains = nftnl_chain_list_alloc();
+                       if (!h->cache->table[type].chains)
+                               return -1;
+               }
+       } else if (!h->cache->table[t->type].chains) {
+               h->cache->table[t->type].chains = nftnl_chain_list_alloc();
+               if (!h->cache->table[t->type].chains)
                        return -1;
        }
 
        nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
                                        NLM_F_DUMP, h->seq);
 
-       ret = mnl_talk(h, nlh, nftnl_chain_list_cb, h);
+       ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
        if (ret < 0 && errno == EINTR)
                assert(nft_restart(h) >= 0);
 
@@ -224,10 +247,14 @@ static int nft_rule_list_update(struct nftnl_chain *c, 
void *data)
        return 0;
 }
 
-static int fetch_rule_cache(struct nft_handle *h)
+static int fetch_rule_cache(struct nft_handle *h, const struct builtin_table 
*t)
 {
        int i;
 
+       if (t)
+               return nftnl_chain_list_foreach(h->cache->table[t->type].chains,
+                                               nft_rule_list_update, h);
+
        for (i = 0; i < NFT_TABLE_MAX; i++) {
                enum nft_table_type type = h->tables[i].type;
 
@@ -241,7 +268,8 @@ static int fetch_rule_cache(struct nft_handle *h)
        return 0;
 }
 
-static void __nft_build_cache(struct nft_handle *h, enum nft_cache_level level)
+static void __nft_build_cache(struct nft_handle *h, enum nft_cache_level level,
+                             const struct builtin_table *t)
 {
        uint32_t genid_start, genid_stop;
 
@@ -260,12 +288,12 @@ retry:
                        break;
                /* fall through */
        case NFT_CL_TABLES:
-               fetch_chain_cache(h);
+               fetch_chain_cache(h, t);
                if (level == NFT_CL_CHAINS)
                        break;
                /* fall through */
        case NFT_CL_CHAINS:
-               fetch_rule_cache(h);
+               fetch_rule_cache(h, t);
                if (level == NFT_CL_RULES)
                        break;
                /* fall through */
@@ -279,14 +307,18 @@ retry:
                goto retry;
        }
 
-       h->cache_level = level;
+       if (!t)
+               h->cache_level = level;
+       else if (h->cache_level < NFT_CL_TABLES)
+               h->cache_level = NFT_CL_TABLES;
+
        h->nft_genid = genid_start;
 }
 
 void nft_build_cache(struct nft_handle *h)
 {
        if (h->cache_level < NFT_CL_RULES)
-               __nft_build_cache(h, NFT_CL_RULES);
+               __nft_build_cache(h, NFT_CL_RULES, NULL);
 }
 
 void nft_fake_cache(struct nft_handle *h)
@@ -385,7 +417,7 @@ void nft_rebuild_cache(struct nft_handle *h)
                __nft_flush_cache(h);
 
        h->cache_level = NFT_CL_NONE;
-       __nft_build_cache(h, level);
+       __nft_build_cache(h, level, NULL);
 }
 
 void nft_release_cache(struct nft_handle *h)
@@ -396,7 +428,7 @@ void nft_release_cache(struct nft_handle *h)
 
 struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
 {
-       __nft_build_cache(h, NFT_CL_TABLES);
+       __nft_build_cache(h, NFT_CL_TABLES, NULL);
 
        return h->cache->tables;
 }
@@ -410,7 +442,7 @@ struct nftnl_chain_list *nft_chain_list_get(struct 
nft_handle *h,
        if (!t)
                return NULL;
 
-       __nft_build_cache(h, NFT_CL_CHAINS);
+       __nft_build_cache(h, NFT_CL_CHAINS, t);
 
        return h->cache->table[t->type].chains;
 }
-- 
2.23.0

Reply via email to