diff options
-rw-r--r-- | include/rule.h | 2 | ||||
-rw-r--r-- | src/evaluate.c | 94 | ||||
-rw-r--r-- | src/mnl.c | 4 | ||||
-rwxr-xr-x | tests/shell/testcases/cache/0003_cache_update_0 | 7 | ||||
-rwxr-xr-x | tests/shell/testcases/transactions/0024rule_0 | 17 | ||||
-rwxr-xr-x | tests/shell/testcases/transactions/0025rule_0 | 21 | ||||
-rw-r--r-- | tests/shell/testcases/transactions/dumps/0024rule_0.nft | 8 | ||||
-rw-r--r-- | tests/shell/testcases/transactions/dumps/0025rule_0.nft | 6 |
8 files changed, 139 insertions, 20 deletions
diff --git a/include/rule.h b/include/rule.h index 8ccdc2e1..dd9df9ec 100644 --- a/include/rule.h +++ b/include/rule.h @@ -73,6 +73,8 @@ struct handle { struct position_spec position; struct position_spec index; uint32_t set_id; + uint32_t rule_id; + uint32_t position_id; }; extern void handle_merge(struct handle *dst, const struct handle *src); diff --git a/src/evaluate.c b/src/evaluate.c index b9660d77..39101b48 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -3180,13 +3180,29 @@ static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft) return 0; } -/* Convert rule's handle.index into handle.position. */ -static int rule_translate_index(struct eval_ctx *ctx, struct rule *rule) +/* make src point at dst, either via handle.position or handle.position_id */ +static void link_rules(struct rule *src, struct rule *dst) { + static uint32_t ref_id = 0; + + if (dst->handle.handle.id) { + /* dst is in kernel, make src reference it by handle */ + src->handle.position.id = dst->handle.handle.id; + src->handle.position.location = src->handle.index.location; + return; + } + + /* dst is not in kernel, make src reference it by per-transaction ID */ + if (!dst->handle.rule_id) + dst->handle.rule_id = ++ref_id; + src->handle.position_id = dst->handle.rule_id; +} + +static int rule_cache_update(struct eval_ctx *ctx, enum cmd_ops op) +{ + struct rule *rule = ctx->rule, *ref = NULL; struct table *table; struct chain *chain; - uint64_t index = 0; - struct rule *r; table = table_lookup(&rule->handle, &ctx->nft->cache); if (!table) @@ -3196,21 +3212,59 @@ static int rule_translate_index(struct eval_ctx *ctx, struct rule *rule) if (!chain) return chain_not_found(ctx); - list_for_each_entry(r, &chain->rules, list) { - if (++index < rule->handle.index.id) - continue; - rule->handle.position.id = r->handle.handle.id; - rule->handle.position.location = rule->handle.index.location; + if (rule->handle.index.id) { + ref = rule_lookup_by_index(chain, rule->handle.index.id); + if (!ref) + return cmd_error(ctx, &rule->handle.index.location, + "Could not process rule: %s", + strerror(ENOENT)); + + link_rules(rule, ref); + } else if (rule->handle.handle.id) { + ref = rule_lookup(chain, rule->handle.handle.id); + if (!ref) + return cmd_error(ctx, &rule->handle.handle.location, + "Could not process rule: %s", + strerror(ENOENT)); + } else if (rule->handle.position.id) { + ref = rule_lookup(chain, rule->handle.position.id); + if (!ref) + return cmd_error(ctx, &rule->handle.position.location, + "Could not process rule: %s", + strerror(ENOENT)); + } + + switch (op) { + case CMD_INSERT: + rule_get(rule); + if (ref) + list_add_tail(&rule->list, &ref->list); + else + list_add(&rule->list, &chain->rules); + break; + case CMD_ADD: + rule_get(rule); + if (ref) + list_add(&rule->list, &ref->list); + else + list_add_tail(&rule->list, &chain->rules); + break; + case CMD_REPLACE: + rule_get(rule); + list_add(&rule->list, &ref->list); + /* fall through */ + case CMD_DELETE: + list_del(&ref->list); + rule_free(ref); + break; + default: break; } - if (!rule->handle.position.id) - return cmd_error(ctx, &rule->handle.index.location, - "Could not process rule: %s", - strerror(ENOENT)); return 0; } -static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule) +static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule, + enum cmd_ops op) { struct stmt *stmt, *tstmt = NULL; struct error_record *erec; @@ -3238,11 +3292,11 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule) return -1; } - if (rule->handle.index.id && - rule_translate_index(ctx, rule)) - return -1; + /* add rules to cache only if it is complete enough to contain them */ + if (!cache_is_complete(&ctx->nft->cache, CMD_LIST)) + return 0; - return 0; + return rule_cache_update(ctx, op); } static uint32_t str2hooknum(uint32_t family, const char *hook) @@ -3323,7 +3377,7 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain) list_for_each_entry(rule, &chain->rules, list) { handle_merge(&rule->handle, &chain->handle); - if (rule_evaluate(ctx, rule) < 0) + if (rule_evaluate(ctx, rule, CMD_INVALID) < 0) return -1; } return 0; @@ -3410,7 +3464,7 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd) return set_evaluate(ctx, cmd->set); case CMD_OBJ_RULE: handle_merge(&cmd->rule->handle, &cmd->handle); - return rule_evaluate(ctx, cmd->rule); + return rule_evaluate(ctx, cmd->rule, cmd->op); case CMD_OBJ_CHAIN: return chain_evaluate(ctx, cmd->chain); case CMD_OBJ_TABLE: @@ -378,6 +378,10 @@ int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd, nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name); if (h->position.id) nftnl_rule_set_u64(nlr, NFTNL_RULE_POSITION, h->position.id); + if (h->rule_id) + nftnl_rule_set_u32(nlr, NFTNL_RULE_ID, h->rule_id); + if (h->position_id) + nftnl_rule_set_u32(nlr, NFTNL_RULE_POSITION_ID, h->position_id); netlink_linearize_rule(ctx, nlr, rule); nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch), diff --git a/tests/shell/testcases/cache/0003_cache_update_0 b/tests/shell/testcases/cache/0003_cache_update_0 index fa9b5df3..05edc9c7 100755 --- a/tests/shell/testcases/cache/0003_cache_update_0 +++ b/tests/shell/testcases/cache/0003_cache_update_0 @@ -34,6 +34,9 @@ EOF # add rule ip t4 c meta l4proto icmp accept -> rule to reference in next step # add rule ip t4 c index 0 drop -> index 0 is not found due to rule cache not # being updated +# add rule ip t4 c index 2 drop -> index 2 is not found due to igmp rule being +# in same transaction and therefore not having +# an allocated handle $NFT -i >/dev/null <<EOF add table ip t4; add chain ip t4 c add rule ip t4 c meta l4proto icmp accept @@ -41,3 +44,7 @@ EOF $NFT -f - >/dev/null <<EOF add rule ip t4 c index 0 drop EOF +$NFT -f - >/dev/null <<EOF +add rule ip t4 c meta l4proto igmp accept +add rule ip t4 c index 2 drop +EOF diff --git a/tests/shell/testcases/transactions/0024rule_0 b/tests/shell/testcases/transactions/0024rule_0 new file mode 100755 index 00000000..4c1ac41d --- /dev/null +++ b/tests/shell/testcases/transactions/0024rule_0 @@ -0,0 +1,17 @@ +#!/bin/bash + +RULESET="flush ruleset +add table x +add chain x y +add rule x y accept comment rule1 +add rule x y accept comment rule4 +add rule x y index 0 accept comment rule2 +insert rule x y index 2 accept comment rule3" + +$NFT -f - <<< "$RULESET" && \ + $NFT -f - <<< "$RULESET" && \ + echo "$RULESET" | tr '\n' ';' | $NFT -i >/dev/null && \ + exit 0 +echo "E: intra-transaction rule reference failed" +exit 1 + diff --git a/tests/shell/testcases/transactions/0025rule_0 b/tests/shell/testcases/transactions/0025rule_0 new file mode 100755 index 00000000..d72d5cfc --- /dev/null +++ b/tests/shell/testcases/transactions/0025rule_0 @@ -0,0 +1,21 @@ +#!/bin/bash + +# make sure stored delete/replace rule commands are correctly applied + +set -e + +$NFT -f - <<EOF +flush ruleset +table x { + chain y { + accept + log + } +} +EOF + +$NFT -f - <<EOF +replace rule x y handle 2 log +delete rule x y handle 3 +add rule x y index 0 drop +EOF diff --git a/tests/shell/testcases/transactions/dumps/0024rule_0.nft b/tests/shell/testcases/transactions/dumps/0024rule_0.nft new file mode 100644 index 00000000..7860ff65 --- /dev/null +++ b/tests/shell/testcases/transactions/dumps/0024rule_0.nft @@ -0,0 +1,8 @@ +table ip x { + chain y { + accept comment "rule1" + accept comment "rule2" + accept comment "rule3" + accept comment "rule4" + } +} diff --git a/tests/shell/testcases/transactions/dumps/0025rule_0.nft b/tests/shell/testcases/transactions/dumps/0025rule_0.nft new file mode 100644 index 00000000..dcb61ae6 --- /dev/null +++ b/tests/shell/testcases/transactions/dumps/0025rule_0.nft @@ -0,0 +1,6 @@ +table ip x { + chain y { + log + drop + } +} |