summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--iptables/nft-cache.c71
-rw-r--r--iptables/nft-cache.h1
-rw-r--r--iptables/nft.c12
-rw-r--r--iptables/nft.h1
-rw-r--r--iptables/xtables-save.c1
5 files changed, 73 insertions, 13 deletions
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
index 6b6e6da4..8fbf9727 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -223,24 +223,67 @@ int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
h->cache->table[t->type].base_chains[hooknum] = nc;
} else {
- struct nft_chain_list *clist = h->cache->table[t->type].chains;
- struct list_head *pos = &clist->list;
- struct nft_chain *cur;
- const char *n;
-
- list_for_each_entry(cur, &clist->list, head) {
- n = nftnl_chain_get_str(cur->nftnl, NFTNL_CHAIN_NAME);
- if (strcmp(cname, n) <= 0) {
- pos = &cur->head;
- break;
- }
- }
- list_add_tail(&nc->head, pos);
+ list_add_tail(&nc->head,
+ &h->cache->table[t->type].chains->list);
}
hlist_add_head(&nc->hnode, chain_name_hlist(h, t, cname));
return 0;
}
+static void __nft_chain_list_sort(struct list_head *list,
+ int (*cmp)(struct nft_chain *a,
+ struct nft_chain *b))
+{
+ struct nft_chain *pivot, *cur, *sav;
+ LIST_HEAD(sublist);
+
+ if (list_empty(list))
+ return;
+
+ /* grab first item as pivot (dividing) value */
+ pivot = list_entry(list->next, struct nft_chain, head);
+ list_del(&pivot->head);
+
+ /* move any smaller value into sublist */
+ list_for_each_entry_safe(cur, sav, list, head) {
+ if (cmp(pivot, cur) > 0) {
+ list_del(&cur->head);
+ list_add_tail(&cur->head, &sublist);
+ }
+ }
+ /* conquer divided */
+ __nft_chain_list_sort(&sublist, cmp);
+ __nft_chain_list_sort(list, cmp);
+
+ /* merge divided and pivot again */
+ list_add_tail(&pivot->head, &sublist);
+ list_splice(&sublist, list);
+}
+
+static int nft_chain_cmp_byname(struct nft_chain *a, struct nft_chain *b)
+{
+ const char *aname = nftnl_chain_get_str(a->nftnl, NFTNL_CHAIN_NAME);
+ const char *bname = nftnl_chain_get_str(b->nftnl, NFTNL_CHAIN_NAME);
+
+ return strcmp(aname, bname);
+}
+
+int nft_cache_sort_chains(struct nft_handle *h, const char *table)
+{
+ const struct builtin_table *t = nft_table_builtin_find(h, table);
+
+ if (!t)
+ return -1;
+
+ if (h->cache->table[t->type].sorted)
+ return 0;
+
+ __nft_chain_list_sort(&h->cache->table[t->type].chains->list,
+ nft_chain_cmp_byname);
+ h->cache->table[t->type].sorted = true;
+ return 0;
+}
+
struct nftnl_chain_list_cb_data {
struct nft_handle *h;
const struct builtin_table *t;
@@ -663,6 +706,7 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
flush_base_chain_cache(c->table[table->type].base_chains);
nft_chain_foreach(h, tablename, __flush_chain_cache, NULL);
+ c->table[table->type].sorted = false;
if (c->table[table->type].sets)
nftnl_set_list_foreach(c->table[table->type].sets,
@@ -678,6 +722,7 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
if (c->table[i].chains) {
nft_chain_list_free(c->table[i].chains);
c->table[i].chains = NULL;
+ c->table[i].sorted = false;
}
if (c->table[i].sets) {
diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h
index 20d96bee..58a01526 100644
--- a/iptables/nft-cache.h
+++ b/iptables/nft-cache.h
@@ -16,6 +16,7 @@ int flush_rule_cache(struct nft_handle *h, const char *table,
void nft_cache_build(struct nft_handle *h);
int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
struct nftnl_chain *c);
+int nft_cache_sort_chains(struct nft_handle *h, const char *table);
struct nft_chain *
nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
diff --git a/iptables/nft.c b/iptables/nft.c
index bde4ca72..8b14daea 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1754,6 +1754,8 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
return 1;
}
+ nft_cache_sort_chains(h, table);
+
ret = nft_chain_foreach(h, table, nft_rule_flush_cb, &d);
/* the core expects 1 for success and 0 for error */
@@ -1900,6 +1902,9 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
goto out;
}
+ if (verbose)
+ nft_cache_sort_chains(h, table);
+
ret = nft_chain_foreach(h, table, __nft_chain_user_del, &d);
out:
/* the core expects 1 for success and 0 for error */
@@ -2437,6 +2442,8 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
return 1;
}
+ nft_cache_sort_chains(h, table);
+
if (ops->print_table_header)
ops->print_table_header(table);
@@ -2540,6 +2547,8 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
return nft_rule_list_cb(c, &d);
}
+ nft_cache_sort_chains(h, table);
+
/* Dump policies and custom chains first */
nft_chain_foreach(h, table, nft_rule_list_chain_save, &counters);
@@ -3431,6 +3440,9 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
goto err;
}
+ if (verbose)
+ nft_cache_sort_chains(h, table);
+
ret = nft_chain_foreach(h, table, __nft_chain_zero_counters, &d);
err:
/* the core expects 1 for success and 0 for error */
diff --git a/iptables/nft.h b/iptables/nft.h
index 0910f82a..4ac7e009 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -44,6 +44,7 @@ struct nft_cache {
struct nft_chain_list *chains;
struct nftnl_set_list *sets;
bool exists;
+ bool sorted;
} table[NFT_TABLE_MAX];
};
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index d7901c65..cfce0472 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -87,6 +87,7 @@ __do_output(struct nft_handle *h, const char *tablename, void *data)
printf("*%s\n", tablename);
/* Dump out chain names first,
* thereby preventing dependency conflicts */
+ nft_cache_sort_chains(h, tablename);
nft_chain_foreach(h, tablename, nft_chain_save, h);
nft_rule_save(h, tablename, d->format);
if (d->commit)