summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2022-04-14 17:47:30 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2022-04-18 15:03:28 +0200
commite45b4939a8ef4173805ffaad7729654a3a9de916 (patch)
tree21c11a1a2c2323185a5374ec6f70a36d076a24ed
parent3b7b22aed894fa1a8495d654d215a335051f6bf1 (diff)
intervals: fix deletion of multiple ranges with automerge
Iterate over the list of elements to be deleted, then splice one EXPR_F_REMOVE element at a time to update the list of existing sets incrementally. Fixes: 3e8d934e4f722 ("intervals: support to partial deletion with automerge") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--src/intervals.c34
1 files changed, 22 insertions, 12 deletions
diff --git a/src/intervals.c b/src/intervals.c
index 590a2967..e66501c5 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -454,34 +454,44 @@ static void automerge_delete(struct list_head *msgs, struct set *set,
expr_free(ctx.purge);
}
+static int __set_delete(struct list_head *msgs, struct expr *i, struct set *set,
+ struct expr *add, struct expr *init,
+ struct set *existing_set, unsigned int debug_mask)
+{
+ i->flags |= EXPR_F_REMOVE;
+ list_move(&i->list, &existing_set->init->expressions);
+ list_expr_sort(&existing_set->init->expressions);
+
+ return setelem_delete(msgs, set, add, init, existing_set->init, debug_mask);
+}
+
/* detection for unexisting intervals already exists in Linux kernels >= 5.7. */
int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
struct expr *init, unsigned int debug_mask)
{
struct set *existing_set = set->existing_set;
- struct expr *i, *add;
+ struct expr *i, *next, *add;
struct handle h = {};
struct cmd *add_cmd;
+ LIST_HEAD(del_list);
int err;
set_to_range(init);
if (set->automerge)
automerge_delete(msgs, set, init, debug_mask);
- list_for_each_entry(i, &init->expressions, list)
- i->flags |= EXPR_F_REMOVE;
-
set_to_range(existing_set->init);
- list_splice_init(&init->expressions, &existing_set->init->expressions);
-
- list_expr_sort(&existing_set->init->expressions);
-
add = set_expr_alloc(&internal_location, set);
- err = setelem_delete(msgs, set, add, init, existing_set->init, debug_mask);
- if (err < 0) {
- expr_free(add);
- return err;
+ list_splice_init(&init->expressions, &del_list);
+
+ list_for_each_entry_safe(i, next, &del_list, list) {
+ err = __set_delete(msgs, i, set, add, init, existing_set, debug_mask);
+ if (err < 0) {
+ list_splice(&del_list, &init->expressions);
+ expr_free(add);
+ return err;
+ }
}
if (debug_mask & NFT_DEBUG_SEGTREE) {