summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/evaluate.c94
-rw-r--r--src/mnl.c4
2 files changed, 78 insertions, 20 deletions
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:
diff --git a/src/mnl.c b/src/mnl.c
index 83dfb9d2..6ebad28b 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -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),