diff mbox

[3/3,v4,nft] Implement deleting rule by description

Message ID 20160816102126.28662-3-carlosfg@riseup.net
State Changes Requested
Delegated to: Pablo Neira
Headers show

Commit Message

Carlos Falgueras García Aug. 16, 2016, 10:21 a.m. UTC
This patch introduces deletion in a similar fashion as in iptables, thus,
we can delete the first rule that matches our description, for example:

	$ nft list -a ruleset
	table ip t {
		chain c {
			ip saddr 1.1.1.1 counter packets 0 bytes 0 # handle 1
			ip saddr 1.1.1.2 counter packets 0 bytes 0 # handle 2
			ip saddr 1.1.1.2 counter packets 0 bytes 0 # handle 3
			ip saddr 1.1.1.4 counter packets 0 bytes 0 # handle 4
		}
	}
	$ nft delete rule table chain ip saddr 1.1.1.2 counter
	$ nft list -a ruleset
	table ip t {
		chain c {
			ip saddr 1.1.1.1 counter packets 0 bytes 0 # handle 1
			ip saddr 1.1.1.2 counter packets 0 bytes 0 # handle 3
			ip saddr 1.1.1.4 counter packets 0 bytes 0 # handle 4
		}
	}

Also a custom error is thrown when user commits a syntax error:

	$ nft delete rule t c position 3 ...
	<cmdline>:1:17-24: Error: Expected `handle' or rule description
	delete rule t c position 3 ...

Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net>
---
 src/evaluate.c     |  6 ++++++
 src/parser_bison.y | 32 ++++++++++++++++++++++++--------
 src/rule.c         | 45 +++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 73 insertions(+), 10 deletions(-)
diff mbox

Patch

diff --git a/src/evaluate.c b/src/evaluate.c
index 2f94ac6..f7b349b 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2661,7 +2661,13 @@  static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
 
 		return setelem_evaluate(ctx, &cmd->expr);
 	case CMD_OBJ_SET:
+		return 0;
 	case CMD_OBJ_RULE:
+		/* CMD_LIST force caching all ruleset */
+		ret = cache_update(CMD_LIST, ctx->msgs);
+		if (ret < 0)
+			return ret;
+		return rule_evaluate(ctx, cmd->rule);
 	case CMD_OBJ_CHAIN:
 	case CMD_OBJ_TABLE:
 		return 0;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 93c283f..713002e 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -427,8 +427,8 @@  static void location_update(struct location *loc, struct location *rhs, int n)
 %type <cmd>			base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
 %destructor { cmd_free($$); }	base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
 
-%type <handle>			table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
-%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
+%type <handle>			table_spec chain_spec chain_identifier handle_spec position_spec rule_position ruleset_spec
+%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier handle_spec position_spec rule_position ruleset_spec
 %type <handle>			set_spec set_identifier
 %destructor { handle_free(&$$); } set_spec set_identifier
 %type <val>			family_spec family_spec_explicit chain_policy prio_spec
@@ -440,7 +440,7 @@  static void location_update(struct location *loc, struct location *rhs, int n)
 %destructor { close_scope(state); table_free($$); }	table_block_alloc
 %type <chain>			chain_block_alloc chain_block
 %destructor { close_scope(state); chain_free($$); }	chain_block_alloc
-%type <rule>			rule rule_alloc
+%type <rule>			rule ruleid_spec rule_alloc
 %destructor { rule_free($$); }	rule
 
 %type <val>			set_flag_list	set_flag
@@ -747,9 +747,10 @@  add_cmd			:	TABLE		table_spec
 			}
 			;
 
-replace_cmd		:	RULE		ruleid_spec	rule
+replace_cmd		:	RULE		chain_spec	handle_spec	rule
 			{
-				$$ = cmd_alloc(CMD_REPLACE, CMD_OBJ_RULE, &$2, &@$, $3);
+				handle_merge(&$2, &$3);
+				$$ = cmd_alloc(CMD_REPLACE, CMD_OBJ_RULE, &$2, &@$, $4);
 			}
 			;
 
@@ -794,7 +795,7 @@  delete_cmd		:	TABLE		table_spec
 			}
 			|	RULE		ruleid_spec
 			{
-				$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_RULE, &$2, &@$, NULL);
+				$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_RULE, &$2->handle, &@$, $2);
 			}
 			|	SET		set_spec
 			{
@@ -1285,8 +1286,23 @@  rule_position		:	chain_spec
 
 ruleid_spec		:	chain_spec handle_spec
 			{
-				$$ = $1;
-				handle_merge(&$$, &$2);
+				$$ = rule_alloc(&@$, NULL);
+				$$->handle = $1;
+				handle_merge(&$$->handle, &$2);
+			}
+			|
+				chain_spec rule
+			{
+				$$ = $2;
+				handle_merge(&$$->handle, &$1);
+			}
+			|	chain_spec err_recovering error
+			{
+				erec_queue(error(&@3, "Expected `handle' or rule description"),
+					   state->msgs);
+				state->err_recovering = false;
+				$$ = rule_alloc(&@$, NULL);
+				handle_merge(&$$->handle, &$1);
 			}
 			;
 
diff --git a/src/rule.c b/src/rule.c
index 14e57f2..d04c1ca 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -402,6 +402,32 @@  void rule_print(const struct rule *rule)
 		printf(" # handle %" PRIu64, rule->handle.handle.id);
 }
 
+static struct rule *search_first_rule(const struct rule *rule)
+{
+	struct nftnl_rule *nlr1, *nlr2;
+	struct rule *rule_idx;
+	struct table *table;
+	struct chain *chain;
+
+	table = table_lookup(&rule->handle);
+	if (!table)
+		return NULL;
+	chain = chain_lookup(table, &rule->handle);
+	if (!chain)
+		return NULL;
+
+	nlr1 = alloc_nftnl_rule(&rule->handle);
+	netlink_linearize_rule(NULL, nlr1, rule);
+
+	list_for_each_entry(rule_idx, &chain->rules, list) {
+		nlr2 = alloc_nftnl_rule(&rule_idx->handle);
+		netlink_linearize_rule(NULL, nlr2, rule_idx);
+		if (nftnl_rule_cmp(nlr1, nlr2))
+			return rule_idx;
+	}
+	return NULL;
+}
+
 struct rule *rule_lookup(const struct chain *chain, uint64_t handle)
 {
 	struct rule *rule;
@@ -1010,6 +1036,22 @@  static int do_delete_setelems(struct netlink_ctx *ctx, const struct handle *h,
 	return 0;
 }
 
+static int do_delete_rule(struct netlink_ctx *ctx, const struct cmd *cmd)
+{
+	struct rule *rule;
+
+	/* Delete by handle */
+	if (cmd->handle.handle.id)
+		return netlink_del_rule_batch(ctx, &cmd->handle, &cmd->location);
+
+	/* Delete by description */
+	rule = search_first_rule(cmd->rule);
+	if (!rule)
+		return 0;
+	return netlink_del_rule_batch(ctx, &rule->handle,
+				      &rule->handle.position.location);
+}
+
 static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
 {
 	switch (cmd->obj) {
@@ -1018,8 +1060,7 @@  static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
 	case CMD_OBJ_CHAIN:
 		return netlink_delete_chain(ctx, &cmd->handle, &cmd->location);
 	case CMD_OBJ_RULE:
-		return netlink_del_rule_batch(ctx, &cmd->handle,
-					      &cmd->location);
+		return do_delete_rule(ctx, cmd);
 	case CMD_OBJ_SET:
 		return netlink_delete_set(ctx, &cmd->handle, &cmd->location);
 	case CMD_OBJ_SETELEM: