diff mbox

[nft,2/3] parser: allow to reorder chain options

Message ID 1426594385-24063-2-git-send-email-pablo@netfilter.org
State Not Applicable
Delegated to: Pablo Neira
Headers show

Commit Message

Pablo Neira Ayuso March 17, 2015, 12:13 p.m. UTC
This allows all possible combinations to work:

 nft add chain filter input { type filter hook input priority 0 \; }
 nft add chain filter input { priority 0 type filter hook input \; }

Wrt. error reporting, this also improves interaction with humans a bit:

 # nft add chain filter input { type filter hook input \; }
 <cmdline>:1:24-49: Error: missing chain priority
 add chain filter input { type filter hook input ; }
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^

 # nft add chain filter input { type filter hook input priority 0 hook input \; }
 <cmdline>:1:65-69: Error: you cannot set chain hook twice
 add chain filter input { type filter hook input priority 0 hook input ; }
                                                            ^^^^^^^^^^
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/rule.h     |   11 +++++++++++
 src/evaluate.c     |   11 ++++++++++-
 src/parser_bison.y |   54 ++++++++++++++++++++++++++++++++++++----------------
 3 files changed, 59 insertions(+), 17 deletions(-)

Comments

Patrick McHardy March 17, 2015, 12:15 p.m. UTC | #1
On 17.03, Pablo Neira Ayuso wrote:
> This allows all possible combinations to work:
> 
>  nft add chain filter input { type filter hook input priority 0 \; }
>  nft add chain filter input { priority 0 type filter hook input \; }


I don't object to being able to change the order of type and hook,
but priority logically belongs to the hook keyword, why change this?
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pablo Neira Ayuso March 17, 2015, 12:29 p.m. UTC | #2
On Tue, Mar 17, 2015 at 12:15:14PM +0000, Patrick McHardy wrote:
> On 17.03, Pablo Neira Ayuso wrote:
> > This allows all possible combinations to work:
> > 
> >  nft add chain filter input { type filter hook input priority 0 \; }
> >  nft add chain filter input { priority 0 type filter hook input \; }
> 
> 
> I don't object to being able to change the order of type and hook,
> but priority logically belongs to the hook keyword, why change this?

When displaying the chain configuration, this shows in order.

But we're humans and I don't see a good reason why we should force
humans to order things in some specific way.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Patrick McHardy March 17, 2015, 12:42 p.m. UTC | #3
On 17.03, Pablo Neira Ayuso wrote:
> On Tue, Mar 17, 2015 at 12:15:14PM +0000, Patrick McHardy wrote:
> > On 17.03, Pablo Neira Ayuso wrote:
> > > This allows all possible combinations to work:
> > > 
> > >  nft add chain filter input { type filter hook input priority 0 \; }
> > >  nft add chain filter input { priority 0 type filter hook input \; }
> > 
> > 
> > I don't object to being able to change the order of type and hook,
> > but priority logically belongs to the hook keyword, why change this?
> 
> When displaying the chain configuration, this shows in order.
> 
> But we're humans and I don't see a good reason why we should force
> humans to order things in some specific way.

I can see multiple reasons.

First one is, it logically belongs together since the priority is a
property of the hook, similar to that "prefix" belongs to "log" and
"rate" belongs to limit. We (I presume) agree that
"log rate limit 1/sec prefix bla" isn't something we want to support.
In fact this is just the mess that we had in iptables and which
created a lot of problems in the parser.

Which brings us to the second point, having a strict grammar makes
it easier to avoid conflicts in the grammar. I don't suppose we
will ever need a priority which is a property of the type, but
with this patch, it would be impossible.

Next is the confusion created by a loose grammar. If you consider
iproute2, if things don't work people start to google, they find
an example where a different, but equivalent keyword is used,
they get even more confused and start wasting their time be
reordering things or replacing keywords with equivalent ones.

And I simply don't see what we gain by doing this. In fact I don't
even buy that "human" argument, I think its easier to remember
a single well defined case than this exception, which is in fact
also an exception to what we do anywhere else in nftables.

My personal opinion is actually that type and hook should use a
stmt_seperator since they are two seperate things.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/rule.h b/include/rule.h
index 90836bc..b0ea1ba 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -92,6 +92,15 @@  extern void table_free(struct table *table);
 extern void table_add_hash(struct table *table);
 extern struct table *table_lookup(const struct handle *h);
 
+enum chain_obj_flags {
+	CHAIN_OBJ_F_HOOK	= (1 << 0),
+	CHAIN_OBJ_F_TYPE	= (1 << 1),
+	CHAIN_OBJ_F_PRIO	= (1 << 2),
+	CHAIN_OBJ_F_BASE	= (CHAIN_OBJ_F_HOOK |
+				   CHAIN_OBJ_F_TYPE |
+				   CHAIN_OBJ_F_PRIO),
+};
+
 /**
  * enum chain_flags - chain flags
  *
@@ -112,6 +121,7 @@  enum chain_flags {
  * @hooknum:	hook number (base chains)
  * @priority:	hook priority (base chains)
  * @type:	chain type
+ * @obj_flags:	internal object flags (indicates structure field is set)
  * @rules:	rules contained in the chain
  */
 struct chain {
@@ -123,6 +133,7 @@  struct chain {
 	unsigned int		hooknum;
 	int			priority;
 	const char		*type;
+	uint32_t		obj_flags;
 	struct scope		scope;
 	struct list_head	rules;
 };
diff --git a/src/evaluate.c b/src/evaluate.c
index a3484c6..79c49ae 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1804,7 +1804,16 @@  static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
 {
 	struct rule *rule;
 
-	if (chain->flags & CHAIN_F_BASECHAIN) {
+	if (chain->flags & CHAIN_OBJ_F_BASE) {
+		if (!(chain->obj_flags & CHAIN_OBJ_F_HOOK))
+			return chain_error(ctx, chain, "missing chain hook");
+		if (!(chain->obj_flags & CHAIN_OBJ_F_PRIO))
+			return chain_error(ctx, chain, "missing chain priority");
+		if (!(chain->obj_flags & CHAIN_OBJ_F_TYPE))
+			return chain_error(ctx, chain, "missing chain type");
+	}
+
+	if (chain->obj_flags & CHAIN_OBJ_F_HOOK) {
 		chain->hooknum = str2hooknum(chain->handle.family,
 					     chain->hookstr);
 		if (chain->hooknum == NF_INET_NUMHOOKS)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 6fc834d..6fa201d 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -1034,39 +1034,61 @@  type_identifier		:	identifier
 			}
 			;
 
-hook_spec		:	TYPE		STRING		HOOK		STRING		PRIORITY	NUM
+hook_spec		:	hook_options
+			;
+
+hook_options		:	hook_options	hook_option
+			|	hook_option
 			{
-				$<chain>0->type		= chain_type_name_lookup($2);
-				if ($<chain>0->type == NULL) {
-					erec_queue(error(&@2, "unknown chain type %s", $2),
+				$<stmt>$	= $<stmt>0;
+			}
+			;
+
+hook_option		:	TYPE		STRING
+			{
+				if ($<chain>0->flags & CHAIN_OBJ_F_TYPE) {
+					erec_queue(error(&@$, "you cannot set chain type twice"),
 						   state->msgs);
 					YYERROR;
 				}
-				$<chain>0->hookstr	= chain_hookname_lookup($4);
-				if ($<chain>0->hookstr == NULL) {
-					erec_queue(error(&@4, "unknown chain hook %s", $4),
+				$<chain>0->type		= chain_type_name_lookup($2);
+				if ($<chain>0->type == NULL) {
+					erec_queue(error(&@2, "unknown chain type %s", $2),
 						   state->msgs);
 					YYERROR;
 				}
-				$<chain>0->priority	= $6;
-				$<chain>0->flags	|= CHAIN_F_BASECHAIN;
+				$<chain>0->obj_flags	|= CHAIN_OBJ_F_TYPE;
 			}
-			|	TYPE		STRING		HOOK		STRING		PRIORITY	DASH	NUM
+			|	HOOK		STRING
 			{
-				$<chain>0->type		= chain_type_name_lookup($2);
-				if ($<chain>0->type == NULL) {
-					erec_queue(error(&@2, "unknown type name %s", $2),
+				if ($<chain>0->flags & CHAIN_OBJ_F_HOOK) {
+					erec_queue(error(&@$, "you cannot set chain hook twice"),
 						   state->msgs);
 					YYERROR;
 				}
-				$<chain>0->hookstr	= chain_hookname_lookup($4);
+				$<chain>0->hookstr	= chain_hookname_lookup($2);
 				if ($<chain>0->hookstr == NULL) {
-					erec_queue(error(&@4, "unknown hook name %s", $4),
+					erec_queue(error(&@2, "unknown hook name %s", $2),
 						   state->msgs);
 					YYERROR;
 				}
-				$<chain>0->priority	= -$7;
 				$<chain>0->flags	|= CHAIN_F_BASECHAIN;
+				$<chain>0->obj_flags	|= CHAIN_OBJ_F_HOOK;
+			}
+			|	PRIORITY	NUM
+			{
+				if ($<chain>0->flags & CHAIN_OBJ_F_PRIO) {
+					erec_queue(error(&@$, "you cannot set chain priority twice"),
+						   state->msgs);
+					YYERROR;
+				}
+				$<chain>0->priority	= $2;
+				$<chain>0->obj_flags	|= CHAIN_OBJ_F_PRIO;
+			}
+			|	PRIORITY	DASH	NUM
+			{
+				$<chain>0->priority	= -$3;
+				$<chain>0->obj_flags	|= CHAIN_OBJ_F_PRIO;
 			}
 			;