]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
intervals: build list of elements to be added from cache
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 15 Apr 2022 09:40:09 +0000 (11:40 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 18 Apr 2022 13:05:53 +0000 (15:05 +0200)
Loop over the set cache and add elements that have no EXPR_F_KERNEL,
meaning that these are new elements in the set that have resulted
from adjusting/split existing ranges.

This fixes several partial deletions of the same interval in one
command.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/intervals.c

index e66501c571abf4ad4d3acc56658ff908e7fae964..584c69d5189b9936d55419d0c802e5c659f2698b 100644 (file)
@@ -274,58 +274,46 @@ static void remove_elem(struct expr *prev, struct set *set, struct expr *purge)
        }
 }
 
-static void __adjust_elem_left(struct set *set, struct expr *prev, struct expr *i,
-                              struct expr *add)
+static void __adjust_elem_left(struct set *set, struct expr *prev, struct expr *i)
 {
        prev->flags &= ~EXPR_F_KERNEL;
        expr_free(prev->key->left);
        prev->key->left = expr_get(i->key->right);
        mpz_add_ui(prev->key->left->value, prev->key->left->value, 1);
-       list_move(&prev->list, &add->expressions);
+       list_move(&prev->list, &set->existing_set->init->expressions);
 }
 
 static void adjust_elem_left(struct set *set, struct expr *prev, struct expr *i,
-                            struct expr *add, struct expr *purge)
+                            struct expr *purge)
 {
-       struct expr *clone;
-
        remove_elem(prev, set, purge);
-       __adjust_elem_left(set, prev, i, add);
+       __adjust_elem_left(set, prev, i);
 
        list_del(&i->list);
        expr_free(i);
-
-       clone = expr_clone(prev);
-       list_add_tail(&clone->list, &set->existing_set->init->expressions);
 }
 
-static void __adjust_elem_right(struct set *set, struct expr *prev, struct expr *i,
-                               struct expr *add)
+static void __adjust_elem_right(struct set *set, struct expr *prev, struct expr *i)
 {
        prev->flags &= ~EXPR_F_KERNEL;
        expr_free(prev->key->right);
        prev->key->right = expr_get(i->key->left);
        mpz_sub_ui(prev->key->right->value, prev->key->right->value, 1);
-       list_move(&prev->list, &add->expressions);
+       list_move(&prev->list, &set->existing_set->init->expressions);
 }
 
 static void adjust_elem_right(struct set *set, struct expr *prev, struct expr *i,
-                             struct expr *add, struct expr *purge)
+                             struct expr *purge)
 {
-       struct expr *clone;
-
        remove_elem(prev, set, purge);
-       __adjust_elem_right(set, prev, i, add);
+       __adjust_elem_right(set, prev, i);
 
        list_del(&i->list);
        expr_free(i);
-
-       clone = expr_clone(prev);
-       list_add_tail(&clone->list, &set->existing_set->init->expressions);
 }
 
 static void split_range(struct set *set, struct expr *prev, struct expr *i,
-                       struct expr *add, struct expr *purge)
+                       struct expr *purge)
 {
        struct expr *clone;
 
@@ -339,37 +327,33 @@ static void split_range(struct set *set, struct expr *prev, struct expr *i,
        expr_free(clone->key->left);
        clone->key->left = expr_get(i->key->right);
        mpz_add_ui(clone->key->left->value, i->key->right->value, 1);
-       list_move(&clone->list, &add->expressions);
-       clone = expr_clone(clone);
        list_add_tail(&clone->list, &set->existing_set->init->expressions);
 
        expr_free(prev->key->right);
        prev->key->right = expr_get(i->key->left);
        mpz_sub_ui(prev->key->right->value, i->key->left->value, 1);
-       list_move(&prev->list, &add->expressions);
-       clone = expr_clone(prev);
-       list_add_tail(&clone->list, &set->existing_set->init->expressions);
+       list_move(&prev->list, &set->existing_set->init->expressions);
 
        list_del(&i->list);
        expr_free(i);
 }
 
-static int setelem_adjust(struct set *set, struct expr *add, struct expr *purge,
+static int setelem_adjust(struct set *set, struct expr *purge,
                          struct range *prev_range, struct range *range,
                          struct expr *prev, struct expr *i)
 {
        if (mpz_cmp(prev_range->low, range->low) == 0 &&
            mpz_cmp(prev_range->high, range->high) > 0) {
                if (i->flags & EXPR_F_REMOVE)
-                       adjust_elem_left(set, prev, i, add, purge);
+                       adjust_elem_left(set, prev, i, purge);
        } else if (mpz_cmp(prev_range->low, range->low) < 0 &&
                   mpz_cmp(prev_range->high, range->high) == 0) {
                if (i->flags & EXPR_F_REMOVE)
-                       adjust_elem_right(set, prev, i, add, purge);
+                       adjust_elem_right(set, prev, i, purge);
        } else if (mpz_cmp(prev_range->low, range->low) < 0 &&
                   mpz_cmp(prev_range->high, range->high) > 0) {
                if (i->flags & EXPR_F_REMOVE)
-                       split_range(set, prev, i, add, purge);
+                       split_range(set, prev, i, purge);
        } else {
                return -1;
        }
@@ -378,8 +362,8 @@ static int setelem_adjust(struct set *set, struct expr *add, struct expr *purge,
 }
 
 static int setelem_delete(struct list_head *msgs, struct set *set,
-                         struct expr *add, struct expr *purge,
-                         struct expr *elems, unsigned int debug_mask)
+                         struct expr *purge, struct expr *elems,
+                         unsigned int debug_mask)
 {
        struct expr *i, *next, *prev = NULL;
        struct range range, prev_range;
@@ -422,7 +406,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
                                expr_free(i);
                        }
                } else if (set->automerge &&
-                          setelem_adjust(set, add, purge, &prev_range, &range, prev, i) < 0) {
+                          setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) {
                        expr_error(msgs, i, "element does not exist");
                        err = -1;
                        goto err;
@@ -455,14 +439,14 @@ static void automerge_delete(struct list_head *msgs, struct set *set,
 }
 
 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)
+                       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);
+       return setelem_delete(msgs, set, init, existing_set->init, debug_mask);
 }
 
 /* detection for unexisting intervals already exists in Linux kernels >= 5.7. */
@@ -470,7 +454,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, *next, *add;
+       struct expr *i, *next, *add, *clone;
        struct handle h = {};
        struct cmd *add_cmd;
        LIST_HEAD(del_list);
@@ -481,19 +465,25 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
                automerge_delete(msgs, set, init, debug_mask);
 
        set_to_range(existing_set->init);
-       add = set_expr_alloc(&internal_location, set);
 
        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);
+               err = __set_delete(msgs, i, set, init, existing_set, debug_mask);
                if (err < 0) {
                        list_splice(&del_list, &init->expressions);
-                       expr_free(add);
                        return err;
                }
        }
 
+       add = set_expr_alloc(&internal_location, set);
+       list_for_each_entry(i, &existing_set->init->expressions, list) {
+               if (!(i->flags & EXPR_F_KERNEL)) {
+                       clone = expr_clone(i);
+                       list_add_tail(&clone->list, &add->expressions);
+               }
+       }
+
        if (debug_mask & NFT_DEBUG_SEGTREE) {
                list_for_each_entry(i, &init->expressions, list)
                        gmp_printf("remove: [%Zx-%Zx]\n",