diff mbox

[nft,2/3] meta: add short-hand mnemonic for probalistic matching

Message ID 1467704135-9154-3-git-send-email-fw@strlen.de
State Changes Requested
Delegated to: Pablo Neira
Headers show

Commit Message

Florian Westphal July 5, 2016, 7:35 a.m. UTC
Allow users to use a simpler way to specify probalistic matching, e. g.:

meta probability 0.5		(match approx. every 2nd packet)
meta probability 0.001		(match approx. once every 1000 packets)

nft list will still show
meta random <= 2147483647
meta random <= 4294967

a followup patch will hide this internal representation (comparing
random 32 bit value with the scaled constant) -- we will munge the
expression statement and turn it into a special-cased meta one during
netlink delinearization.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/meta.h     |  4 ++++
 src/meta.c         | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/parser_bison.y | 19 +++++++++++++++++++
 src/scanner.l      |  5 +++++
 4 files changed, 83 insertions(+)

Comments

Pablo Neira Ayuso July 14, 2016, 10:41 a.m. UTC | #1
On Tue, Jul 05, 2016 at 09:35:34AM +0200, Florian Westphal wrote:
> Allow users to use a simpler way to specify probalistic matching, e. g.:
> 
> meta probability 0.5		(match approx. every 2nd packet)
> meta probability 0.001		(match approx. once every 1000 packets)
> 
> nft list will still show
> meta random <= 2147483647
> meta random <= 4294967

I don't like this asymmetry.

What is the usecase for 'meta random' out of this probability case that
maps to what xt_statistics offers?
--
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
Florian Westphal July 14, 2016, 10:52 a.m. UTC | #2
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Tue, Jul 05, 2016 at 09:35:34AM +0200, Florian Westphal wrote:
> > Allow users to use a simpler way to specify probalistic matching, e. g.:
> > 
> > meta probability 0.5		(match approx. every 2nd packet)
> > meta probability 0.001		(match approx. once every 1000 packets)
> > 
> > nft list will still show
> > meta random <= 2147483647
> > meta random <= 4294967
> 
> I don't like this asymmetry.

Its changed in patch #3 when adding the shorthand reverse translation.

> What is the usecase for 'meta random' out of this probability case that
> maps to what xt_statistics offers?

Nothing, but the meta random might be interesting to e.g. set random
(ct)mark for load balancing purposes.
--
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 July 14, 2016, 11:32 a.m. UTC | #3
On Thu, Jul 14, 2016 at 12:52:18PM +0200, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > On Tue, Jul 05, 2016 at 09:35:34AM +0200, Florian Westphal wrote:
> > > Allow users to use a simpler way to specify probalistic matching, e. g.:
> > > 
> > > meta probability 0.5		(match approx. every 2nd packet)
> > > meta probability 0.001		(match approx. once every 1000 packets)
> > > 
> > > nft list will still show
> > > meta random <= 2147483647
> > > meta random <= 4294967
> > 
> > I don't like this asymmetry.
> 
> Its changed in patch #3 when adding the shorthand reverse
> translation.

But if the user introduces a meta random value that can be mapped to
probability datatype, we would still hit this asymmetry, right? So the
guess game would fail and the user would get confused.

> > What is the usecase for 'meta random' out of this probability case that
> > maps to what xt_statistics offers?
> 
> Nothing, but the meta random might be interesting to e.g. set random
> (ct)mark for load balancing purposes.

Could you have a look at the libnftnl userdata tlv infrastructure? We
can probably place this information the RULE_USERDATA so we provide an
explicit indication to userspace of how to interpret this.  Currently
this is only used for rule comments, but we can stash this
how-to-interpret-this information there.

The idea is to keep this information around as context in the
delinearize step, so we can replace the default datatype that is
assigned to the one that displays this as a probability from the
rule_parse_postprocess() phase.
--
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
Florian Westphal July 14, 2016, 12:08 p.m. UTC | #4
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> But if the user introduces a meta random value that can be mapped to
> probability datatype, we would still hit this asymmetry, right? So the
> guess game would fail and the user would get confused.

Yes, but thats not really different from what we do with dependency
removal, e.g. with 'ip protocol tcp tcp dport 22', the 'ip protocol tcp'
is still elided from list output since its redundant.

> > Nothing, but the meta random might be interesting to e.g. set random
> > (ct)mark for load balancing purposes.
> 
> Could you have a look at the libnftnl userdata tlv infrastructure? We
> can probably place this information the RULE_USERDATA so we provide an
> explicit indication to userspace of how to interpret this.  Currently
> this is only used for rule comments, but we can stash this
> how-to-interpret-this information there.

Sure, I will have a look.  It might take a while though.
--
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 July 14, 2016, 12:17 p.m. UTC | #5
On Thu, Jul 14, 2016 at 02:08:40PM +0200, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > But if the user introduces a meta random value that can be mapped to
> > probability datatype, we would still hit this asymmetry, right? So the
> > guess game would fail and the user would get confused.
> 
> Yes, but thats not really different from what we do with dependency
> removal, e.g. with 'ip protocol tcp tcp dport 22', the 'ip protocol tcp'
> is still elided from list output since its redundant.

Dependencies are a different thing, they are dealing with redundant
information. This is about what datatype userspace should use to
intepret data.

> > > Nothing, but the meta random might be interesting to e.g. set random
> > > (ct)mark for load balancing purposes.
> > 
> > Could you have a look at the libnftnl userdata tlv infrastructure? We
> > can probably place this information the RULE_USERDATA so we provide an
> > explicit indication to userspace of how to interpret this.  Currently
> > this is only used for rule comments, but we can stash this
> > how-to-interpret-this information there.
> 
> Sure, I will have a look.  It might take a while though.

Thanks.
--
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/meta.h b/include/meta.h
index f25b147..aafd232 100644
--- a/include/meta.h
+++ b/include/meta.h
@@ -26,6 +26,10 @@  struct meta_template {
 extern struct expr *meta_expr_alloc(const struct location *loc,
 				    enum nft_meta_keys key);
 
+struct error_record *meta_probability_parse(const struct location *loc,
+				    const char *s, uint32_t *v);
+struct stmt *meta_stmt_meta_probability(const struct location *loc, uint32_t p);
+
 struct stmt *meta_stmt_meta_iiftype(const struct location *loc, uint16_t type);
 
 const struct datatype ifindex_type;
diff --git a/src/meta.c b/src/meta.c
index 8b1a2fc..2b0d5f0 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -364,6 +364,47 @@  static const struct datatype devgroup_type = {
 	.flags		= DTYPE_F_PREFIX,
 };
 
+#define META_PROB_FMT	"%.9f"
+
+/* UINT_MAX == 1.0, UINT_MAX/2 == 0.5, etc. */
+struct error_record *meta_probability_parse(const struct location *loc, const char *str,
+					    uint32_t *value)
+{
+		static const uint64_t precision = 1000000000;
+		uint64_t tmp;
+		char *end;
+		double d, scaled;
+
+		errno = 0;
+		d = strtod(str, &end);
+
+		if (errno)
+			return error(loc, "Could not parse probability %s: %s", str, strerror(errno));
+		if (end == str)
+			return error(loc, "Could not parse probability %s", str);
+
+		scaled = d;
+		scaled *= precision;
+		tmp = (uint64_t) scaled;
+
+		if (tmp > UINT_MAX)
+			goto overflow;
+
+		tmp *= UINT_MAX;
+		tmp /= precision;
+
+		if (tmp >= UINT_MAX)
+			goto overflow;
+
+		*value = (uint32_t) tmp;
+		if (*value == 0)
+			return error(loc, "Probability " META_PROB_FMT " too %s", d, "small");
+
+		return NULL;
+ overflow:
+		return error(loc, "Probability " META_PROB_FMT " too %s", d, "big");
+}
+
 static const struct meta_template meta_templates[] = {
 	[NFT_META_LEN]		= META_TEMPLATE("length",    &integer_type,
 						4 * 8, BYTEORDER_HOST_ENDIAN),
@@ -618,3 +659,17 @@  struct stmt *meta_stmt_meta_iiftype(const struct location *loc, uint16_t type)
 	dep = relational_expr_alloc(loc, OP_EQ, left, right);
 	return expr_stmt_alloc(&dep->location, dep);
 }
+
+struct stmt *meta_stmt_meta_probability(const struct location *loc, uint32_t p)
+{
+	struct expr *e, *left, *right;
+
+	left = meta_expr_alloc(loc, NFT_META_PRANDOM);
+	right = constant_expr_alloc(loc, &integer_type,
+				    BYTEORDER_HOST_ENDIAN,
+				    sizeof(p) * BITS_PER_BYTE, &p);
+
+	e = relational_expr_alloc(loc, OP_LTE, left, right);
+
+	return expr_stmt_alloc(&e->location, e);
+}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index fdbfed9..dceb90f 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2367,6 +2367,25 @@  meta_stmt		:	META	meta_key	SET	expr
 			{
 				$$ = meta_stmt_alloc(&@$, $1, $3);
 			}
+			|	META	STRING		STRING
+			{
+				struct error_record *erec;
+				uint32_t value;
+
+				if (strcmp($2, "probability") != 0) {
+					erec_queue(error(&@$, "unknown meta option %s", $2),
+						   state->msgs);
+					YYERROR;
+				}
+
+				erec = meta_probability_parse(&@$, $3, &value);
+				if (erec != NULL) {
+					erec_queue(erec, state->msgs);
+					YYERROR;
+				}
+
+				$$ = meta_stmt_meta_probability(&@$, value);
+			}
 			;
 
 ct_expr			: 	CT	ct_key
diff --git a/src/scanner.l b/src/scanner.l
index 88669d0..29ffe94 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -110,6 +110,7 @@  digit		[0-9]
 hexdigit	[0-9a-fA-F]
 decstring	{digit}+
 hexstring	0[xX]{hexdigit}+
+probability	0.{decstring}
 range		({decstring}?:{decstring}?)
 letter		[a-zA-Z]
 string		({letter})({letter}|{digit}|[/\-_\.])*
@@ -490,6 +491,10 @@  addrstring	({macaddr}|{ip4addr}|{ip6addr})
 				return NUM;
 			}
 
+{probability}		{
+				yylval->string = xstrdup(yytext);
+				return STRING;
+			}
 {hexstring}		{
 				errno = 0;
 				yylval->val = strtoull(yytext, NULL, 0);