diff options
Diffstat (limited to 'src/intervals.c')
-rw-r--r-- | src/intervals.c | 96 |
1 files changed, 56 insertions, 40 deletions
diff --git a/src/intervals.c b/src/intervals.c index e61adc76..6c3f36fe 100644 --- a/src/intervals.c +++ b/src/intervals.c @@ -6,11 +6,15 @@ * later) as published by the Free Software Foundation. */ +#include <nft.h> + #include <nftables.h> #include <expression.h> #include <intervals.h> #include <rule.h> +static void set_to_range(struct expr *init); + static void setelem_expr_to_range(struct expr *expr) { unsigned char data[sizeof(struct in6_addr) * BITS_PER_BYTE]; @@ -24,6 +28,9 @@ static void setelem_expr_to_range(struct expr *expr) case EXPR_RANGE: break; case EXPR_PREFIX: + if (expr->key->prefix->etype != EXPR_VALUE) + BUG("Prefix for unexpected type %d", expr->key->prefix->etype); + mpz_init(rop); mpz_bitmask(rop, expr->key->len - expr->key->prefix_len); if (expr_basetype(expr)->type == TYPE_STRING) @@ -118,6 +125,26 @@ static bool merge_ranges(struct set_automerge_ctx *ctx, return false; } +static void set_sort_splice(struct expr *init, struct set *set) +{ + struct set *existing_set = set->existing_set; + + set_to_range(init); + list_expr_sort(&init->expressions); + + if (!existing_set || existing_set->errors) + return; + + if (existing_set->init) { + set_to_range(existing_set->init); + list_splice_sorted(&existing_set->init->expressions, + &init->expressions); + init_list_head(&existing_set->init->expressions); + } else { + existing_set->init = set_expr_alloc(&internal_location, set); + } +} + static void setelem_automerge(struct set_automerge_ctx *ctx) { struct expr *i, *next, *prev = NULL; @@ -193,7 +220,7 @@ static struct expr *interval_expr_key(struct expr *i) return elem; } -void set_to_range(struct expr *init) +static void set_to_range(struct expr *init) { struct expr *i, *elem; @@ -216,21 +243,13 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set, struct cmd *purge_cmd; struct handle h = {}; - if (existing_set) { - if (existing_set->init) { - list_splice_init(&existing_set->init->expressions, - &init->expressions); - } else { - existing_set->init = set_expr_alloc(&internal_location, - set); - } + if (set->flags & NFT_SET_MAP) { + set_to_range(init); + list_expr_sort(&init->expressions); + return 0; } - set_to_range(init); - list_expr_sort(&init->expressions); - - if (set->flags & NFT_SET_MAP) - return 0; + set_sort_splice(init, set); ctx.purge = set_expr_alloc(&internal_location, set); @@ -404,8 +423,13 @@ static int setelem_delete(struct list_head *msgs, struct set *set, list_del(&i->list); expr_free(i); } - } else if (set->automerge && - setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) { + } else if (set->automerge) { + if (setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) { + expr_error(msgs, i, "element does not exist"); + err = -1; + goto err; + } + } else if (i->flags & EXPR_F_REMOVE) { expr_error(msgs, i, "element does not exist"); err = -1; goto err; @@ -442,7 +466,7 @@ static int __set_delete(struct list_head *msgs, struct expr *i, struct set *set, unsigned int debug_mask) { i->flags |= EXPR_F_REMOVE; - list_move(&i->list, &existing_set->init->expressions); + list_move_tail(&i->list, &existing_set->init->expressions); list_expr_sort(&existing_set->init->expressions); return setelem_delete(msgs, set, init, existing_set->init, debug_mask); @@ -463,7 +487,11 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set, if (set->automerge) automerge_delete(msgs, set, init, debug_mask); - set_to_range(existing_set->init); + if (existing_set->init) { + set_to_range(existing_set->init); + } else { + existing_set->init = set_expr_alloc(&internal_location, set); + } list_splice_init(&init->expressions, &del_list); @@ -486,14 +514,14 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set, if (debug_mask & NFT_DEBUG_SEGTREE) { list_for_each_entry(i, &init->expressions, list) - gmp_printf("remove: [%Zx-%Zx]\n", - i->key->left->value, i->key->right->value); + pr_gmp_debug("remove: [%Zx-%Zx]\n", + i->key->left->value, i->key->right->value); list_for_each_entry(i, &add->expressions, list) - gmp_printf("add: [%Zx-%Zx]\n", - i->key->left->value, i->key->right->value); + pr_gmp_debug("add: [%Zx-%Zx]\n", + i->key->left->value, i->key->right->value); list_for_each_entry(i, &existing_set->init->expressions, list) - gmp_printf("existing: [%Zx-%Zx]\n", - i->key->left->value, i->key->right->value); + pr_gmp_debug("existing: [%Zx-%Zx]\n", + i->key->left->value, i->key->right->value); } if (list_empty(&add->expressions)) { @@ -540,8 +568,7 @@ static int setelem_overlap(struct list_head *msgs, struct set *set, } if (mpz_cmp(prev_range.low, range.low) == 0 && - mpz_cmp(prev_range.high, range.high) == 0 && - (elem->flags & EXPR_F_KERNEL || prev->flags & EXPR_F_KERNEL)) + mpz_cmp(prev_range.high, range.high) == 0) goto next; if (mpz_cmp(prev_range.low, range.low) <= 0 && @@ -589,18 +616,7 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init) struct expr *i, *n, *clone; int err; - if (existing_set) { - if (existing_set->init) { - list_splice_init(&existing_set->init->expressions, - &init->expressions); - } else { - existing_set->init = set_expr_alloc(&internal_location, - set); - } - } - - set_to_range(init); - list_expr_sort(&init->expressions); + set_sort_splice(init, set); err = setelem_overlap(msgs, set, init); @@ -700,9 +716,9 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add) if (set->key->byteorder == BYTEORDER_HOST_ENDIAN) mpz_switch_byteorder(expr->value, set->key->len / BITS_PER_BYTE); - newelem = set_elem_expr_alloc(&internal_location, expr); + newelem = set_elem_expr_alloc(&expr->location, expr); if (i->etype == EXPR_MAPPING) { - newelem = mapping_expr_alloc(&internal_location, + newelem = mapping_expr_alloc(&expr->location, newelem, expr_get(i->right)); } |