* [PATCH nft] src: allow to map key to nfqueue number
@ 2024-10-25 7:47 Florian Westphal
2024-11-06 13:28 ` Pablo Neira Ayuso
0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2024-10-25 7:47 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Allow to specify a numeric queue id as part of a map.
The parser side is easy, but the reverse direction (listing) is not.
'queue' is a statement, it doesn't have an expression.
Add a generic 'typeof_data_expr' as a placeholder, this is used only
for udata build/parse, it stores the "key" (the parser token, here
"queue") as udata in kernel and can then restore the original key.
Integer expression doesn't work for listing because it doesn't tell what
frontend token should be shown.
'string' doesn't work as a placeholder either because we must use a
16 bit length type, as thats what the kernel needs to reserve in the
map to hold the queue id.
Add a dumpfile to validate parser & output.
JSON support is missing because JSON doesn't allow any sort of typeof
use at this time.
Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1455
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/expression.h | 15 ++-
include/json.h | 2 +
src/expression.c | 112 ++++++++++++++++++
src/json.c | 6 +
src/parser_bison.y | 4 +
tests/shell/testcases/nft-f/dumps/nfqueue.nft | 11 ++
tests/shell/testcases/nft-f/nfqueue | 6 +
7 files changed, 155 insertions(+), 1 deletion(-)
create mode 100644 tests/shell/testcases/nft-f/dumps/nfqueue.nft
create mode 100755 tests/shell/testcases/nft-f/nfqueue
diff --git a/include/expression.h b/include/expression.h
index 8982110cce95..10733be7c02c 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -48,6 +48,7 @@
* @EXPR_XFRM XFRM (ipsec) expression
* @EXPR_SET_ELEM_CATCHALL catchall element expression
* @EXPR_FLAGCMP flagcmp expression
+ * @EXPR_TYPEOF: integer basetype encapsulation for udata
*/
enum expr_types {
EXPR_INVALID,
@@ -80,8 +81,9 @@ enum expr_types {
EXPR_XFRM,
EXPR_SET_ELEM_CATCHALL,
EXPR_FLAGCMP,
+ EXPR_TYPEOF,
- EXPR_MAX = EXPR_FLAGCMP
+ EXPR_MAX = EXPR_TYPEOF,
};
enum ops {
@@ -217,6 +219,10 @@ enum expr_flags {
EXPR_F_REMOVE = 0x80,
};
+enum expr_typeof_key {
+ EXPR_TYPEOF_NFQUEUE_ID,
+};
+
#include <payload.h>
#include <exthdr.h>
#include <fib.h>
@@ -397,6 +403,10 @@ struct expr {
struct expr *mask;
struct expr *value;
} flagcmp;
+ struct {
+ /* EXPR_TYPEOF */
+ enum expr_typeof_key key;
+ } datatype;
};
};
@@ -447,6 +457,9 @@ extern struct expr *relational_expr_alloc(const struct location *loc, enum ops o
extern void relational_expr_pctx_update(struct proto_ctx *ctx,
const struct expr *expr);
+extern struct expr *typeof_expr_alloc(const struct location *loc,
+ enum expr_typeof_key key);
+
extern struct expr *verdict_expr_alloc(const struct location *loc,
int verdict, struct expr *chain);
diff --git a/include/json.h b/include/json.h
index 39be8928e8ee..5b145cd51a0a 100644
--- a/include/json.h
+++ b/include/json.h
@@ -51,6 +51,7 @@ json_t *hash_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *fib_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *constant_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *socket_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *typeof_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *osf_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *xfrm_expr_json(const struct expr *expr, struct output_ctx *octx);
@@ -158,6 +159,7 @@ EXPR_PRINT_STUB(hash_expr)
EXPR_PRINT_STUB(fib_expr)
EXPR_PRINT_STUB(constant_expr)
EXPR_PRINT_STUB(socket_expr)
+EXPR_PRINT_STUB(typeof_expr)
EXPR_PRINT_STUB(osf_expr)
EXPR_PRINT_STUB(xfrm_expr)
diff --git a/src/expression.c b/src/expression.c
index c0cb7f22eb73..d74addb35c66 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -332,6 +332,117 @@ struct expr *symbol_expr_alloc(const struct location *loc,
return expr;
}
+#define NFTNL_UDATA_TYPEOF_KEY 0
+#define NFTNL_UDATA_TYPEOF_MAX NFTNL_UDATA_TYPEOF_KEY
+
+static int typeof_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_TYPEOF_KEY, expr->datatype.key))
+ return -1;
+
+ return 0;
+}
+
+static int typeof_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+ uint32_t value;
+
+ switch (type) {
+ case NFTNL_UDATA_TYPEOF_KEY:
+ if (len != sizeof(uint32_t))
+ return -1;
+
+ value = nftnl_udata_get_u32(attr);
+ switch (value) {
+ case EXPR_TYPEOF_NFQUEUE_ID:
+ break;
+ default:
+ return -1;
+ }
+
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *typeof_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_TYPEOF_MAX + 1] = {};
+ enum expr_typeof_key key;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ typeof_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_TYPEOF_KEY])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_TYPEOF_KEY]);
+
+ return typeof_expr_alloc(&internal_location, key);
+}
+
+static const char * const typeof_key_str[] = {
+ [EXPR_TYPEOF_NFQUEUE_ID] = "queue",
+};
+
+static void typeof_expr_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ uint32_t v = expr->datatype.key;
+ const char *s = "unknown";
+
+ if (v < array_size(typeof_key_str))
+ s = typeof_key_str[v];
+
+ nft_print(octx, "%s", s);
+}
+
+static bool typeof_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return e1->datatype.key == e2->datatype.key;
+}
+
+const struct expr_ops typeof_expr_ops = {
+ .type = EXPR_TYPEOF,
+ .name = "typeof",
+ .print = typeof_expr_print,
+ .json = typeof_expr_json,
+ .cmp = typeof_expr_cmp,
+ .build_udata = typeof_expr_build_udata,
+ .parse_udata = typeof_expr_parse_udata,
+};
+
+struct expr *typeof_expr_alloc(const struct location *loc,
+ enum expr_typeof_key key)
+{
+ enum byteorder bo = BYTEORDER_INVALID;
+ struct expr *expr;
+ unsigned int len;
+
+ switch (key) {
+ case EXPR_TYPEOF_NFQUEUE_ID:
+ bo = BYTEORDER_HOST_ENDIAN;
+ len = 16;
+ break;
+ }
+
+ expr = expr_alloc(loc, EXPR_TYPEOF, &integer_type, bo, len);
+ expr->datatype.key = key;
+
+ return expr;
+}
+
static void variable_expr_print(const struct expr *expr,
struct output_ctx *octx)
{
@@ -1507,6 +1618,7 @@ static const struct expr_ops *__expr_ops_by_type(enum expr_types etype)
{
switch (etype) {
case EXPR_INVALID: break;
+ case EXPR_TYPEOF: return &typeof_expr_ops;
case EXPR_VERDICT: return &verdict_expr_ops;
case EXPR_SYMBOL: return &symbol_expr_ops;
case EXPR_VARIABLE: return &variable_expr_ops;
diff --git a/src/json.c b/src/json.c
index b1531ff3f4c9..94fd968120a7 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1020,6 +1020,12 @@ json_t *socket_expr_json(const struct expr *expr, struct output_ctx *octx)
socket_templates[expr->socket.key].token);
}
+json_t *typeof_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ /* Need to add support for 'typeof' keyword in json set/map declarations first */
+ return NULL;
+}
+
json_t *osf_expr_json(const struct expr *expr, struct output_ctx *octx)
{
json_t *root;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index e2936d10efe4..7fa114957e3e 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2160,6 +2160,10 @@ typeof_data_expr : INTERVAL typeof_expr
{
$$ = $1;
}
+ | QUEUE
+ {
+ $$ = typeof_expr_alloc(&@$, EXPR_TYPEOF_NFQUEUE_ID);
+ }
;
typeof_expr : primary_expr
diff --git a/tests/shell/testcases/nft-f/dumps/nfqueue.nft b/tests/shell/testcases/nft-f/dumps/nfqueue.nft
new file mode 100644
index 000000000000..7fe3ca669544
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/nfqueue.nft
@@ -0,0 +1,11 @@
+table inet t {
+ map get_queue_id {
+ typeof ip saddr . ip daddr . tcp dport : queue
+ elements = { 127.0.0.1 . 127.0.0.1 . 22 : 1,
+ 127.0.0.1 . 127.0.0.2 . 22 : 2 }
+ }
+
+ chain test {
+ queue flags bypass to ip saddr . ip daddr . tcp dport map @get_queue_id
+ }
+}
diff --git a/tests/shell/testcases/nft-f/nfqueue b/tests/shell/testcases/nft-f/nfqueue
new file mode 100755
index 000000000000..07820b7c4fdd
--- /dev/null
+++ b/tests/shell/testcases/nft-f/nfqueue
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
--
2.45.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH nft] src: allow to map key to nfqueue number
2024-10-25 7:47 [PATCH nft] src: allow to map key to nfqueue number Florian Westphal
@ 2024-11-06 13:28 ` Pablo Neira Ayuso
2024-11-06 13:52 ` Florian Westphal
0 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2024-11-06 13:28 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
Hi Florian,
On Fri, Oct 25, 2024 at 09:47:25AM +0200, Florian Westphal wrote:
[...]
> @@ -447,6 +457,9 @@ extern struct expr *relational_expr_alloc(const struct location *loc, enum ops o
> extern void relational_expr_pctx_update(struct proto_ctx *ctx,
> const struct expr *expr);
>
> +extern struct expr *typeof_expr_alloc(const struct location *loc,
> + enum expr_typeof_key key);
I think it should be possible to follow an alternative path to achieve
this, that is, use integer_expr and attach a new internal datatype,
ie. queue_type, for this queue number.
No need for new TYPE_* in enum, that is only required by
concatenations and this datatype will not ever be used in that case.
For reference, there is also use of this alias datatypes such as
xinteger_type which is used to print integers in hexadecimal.
From userdata path it should be possible to check for this special
internal queue_datatype then encode the queue number type in the TLV.
Thanks.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH nft] src: allow to map key to nfqueue number
2024-11-06 13:28 ` Pablo Neira Ayuso
@ 2024-11-06 13:52 ` Florian Westphal
2024-11-06 14:32 ` Florian Westphal
0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2024-11-06 13:52 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > @@ -447,6 +457,9 @@ extern struct expr *relational_expr_alloc(const struct location *loc, enum ops o
> > extern void relational_expr_pctx_update(struct proto_ctx *ctx,
> > const struct expr *expr);
> >
> > +extern struct expr *typeof_expr_alloc(const struct location *loc,
> > + enum expr_typeof_key key);
>
> I think it should be possible to follow an alternative path to achieve
> this, that is, use integer_expr and attach a new internal datatype,
> ie. queue_type, for this queue number.
>
> No need for new TYPE_* in enum, that is only required by
> concatenations and this datatype will not ever be used in that case.
>
> For reference, there is also use of this alias datatypes such as
> xinteger_type which is used to print integers in hexadecimal.
>
> From userdata path it should be possible to check for this special
> internal queue_datatype then encode the queue number type in the TLV.
I have no idea how to do any of this. I don't even know what a "queue number
type" is.
How on earth do i flip the data type on postprocessing without any idea
what "2 octets worth of data" is?
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH nft] src: allow to map key to nfqueue number
2024-11-06 13:52 ` Florian Westphal
@ 2024-11-06 14:32 ` Florian Westphal
2024-11-06 16:03 ` Pablo Neira Ayuso
0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2024-11-06 14:32 UTC (permalink / raw)
To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel
Florian Westphal <fw@strlen.de> wrote:
> > From userdata path it should be possible to check for this special
> > internal queue_datatype then encode the queue number type in the TLV.
>
> I have no idea how to do any of this. I don't even know what a "queue number
> type" is.
>
> How on earth do i flip the data type on postprocessing without any idea
> what "2 octets worth of data" is?
You seem to dislike EXPR_TYPE; I tried to sketch something but i would
turn EXPR_VALUE into EXPR_TYPE, including EXPR_TYPEOF_NFQUEUE_ID and
the udata build/parse functions, with the addition of a
/* Dummy alias of integer_type for nf_queue id numbers */
const struct datatype integer_queue_type = {
that has no actual function except to override what constant_expr_print()
ends up doing.
TL;DR I give up.
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH nft] src: allow to map key to nfqueue number
2024-11-06 14:32 ` Florian Westphal
@ 2024-11-06 16:03 ` Pablo Neira Ayuso
2024-11-06 23:11 ` Pablo Neira Ayuso
0 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2024-11-06 16:03 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
Hi Florian,
On Wed, Nov 06, 2024 at 03:32:53PM +0100, Florian Westphal wrote:
> Florian Westphal <fw@strlen.de> wrote:
> > > From userdata path it should be possible to check for this special
> > > internal queue_datatype then encode the queue number type in the TLV.
> >
> > I have no idea how to do any of this. I don't even know what a "queue number
> > type" is.
> >
> > How on earth do i flip the data type on postprocessing without any idea
> > what "2 octets worth of data" is?
>
> You seem to dislike EXPR_TYPE; I tried to sketch something but i would
> turn EXPR_VALUE into EXPR_TYPE, including EXPR_TYPEOF_NFQUEUE_ID and
> the udata build/parse functions, with the addition of a
>
> /* Dummy alias of integer_type for nf_queue id numbers */
> const struct datatype integer_queue_type = {
>
> that has no actual function except to override what constant_expr_print()
> ends up doing.
I am fine with your patch, it is perfectly fine to address this in
this way. I just proposed a different way to handle this special case.
I can take a look later today based on your patch, I think I can reuse
90% of it, it is just a subtle detail what I am referring to.
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH nft] src: allow to map key to nfqueue number
2024-11-06 16:03 ` Pablo Neira Ayuso
@ 2024-11-06 23:11 ` Pablo Neira Ayuso
2024-11-06 23:34 ` Pablo Neira Ayuso
0 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2024-11-06 23:11 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
[-- Attachment #1: Type: text/plain, Size: 276 bytes --]
On Wed, Nov 06, 2024 at 05:03:55PM +0100, Pablo Neira Ayuso wrote:
> I can take a look later today based on your patch, I think I can reuse
> 90% of it, it is just a subtle detail what I am referring to.
See attachment, not better than your proposal, just a different focus.
[-- Attachment #2: 0001-src-allow-to-map-key-to-nfqueue-number.patch --]
[-- Type: text/x-diff, Size: 7305 bytes --]
From 26a7503fd5dadf0425515f5647add64a2a9eb404 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Fri, 25 Oct 2024 09:47:25 +0200
Subject: [PATCH] src: allow to map key to nfqueue number
Allow to specify a numeric queue id as part of a map.
The parser side is easy, but the reverse direction (listing) is not.
'queue' is a statement, it doesn't have an expression.
Add a generic 'queue_type' datatype as a TYPE_TYPEOF shim to the real
basetype with constant expressions, this is used only for udata
build/parse, it stores the "key" (the parser token, here "queue") as
udata in kernel and can then restore the original key.
Add a dumpfile to validate parser & output.
JSON support is missing because JSON allow typeof only since quite
recently.
Joint work with Pablo.
Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1455
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/datatype.h | 3 +
src/datatype.c | 17 ++++
src/expression.c | 80 +++++++++++++++++++
src/json. | 0
src/netlink.c | 6 +-
src/parser_bison.y | 4 +
tests/shell/testcases/nft-f/dumps/nfqueue.nft | 11 +++
tests/shell/testcases/nft-f/nfqueue | 6 ++
8 files changed, 126 insertions(+), 1 deletion(-)
create mode 100644 src/json.
create mode 100644 tests/shell/testcases/nft-f/dumps/nfqueue.nft
create mode 100755 tests/shell/testcases/nft-f/nfqueue
diff --git a/include/datatype.h b/include/datatype.h
index 75d6d6b8c628..61c6bf595e9e 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -102,6 +102,8 @@ enum datatypes {
};
#define TYPE_MAX (__TYPE_MAX - 1)
+#define TYPE_TYPEOF __TYPE_MAX
+
#define TYPE_BITS 6
#define TYPE_MASK ((1 << TYPE_BITS) - 1)
@@ -271,6 +273,7 @@ extern const struct datatype boolean_type;
extern const struct datatype priority_type;
extern const struct datatype policy_type;
extern const struct datatype cgroupv2_type;
+extern const struct datatype queue_type;
/* private datatypes for reject statement. */
extern const struct datatype reject_icmp_code_type;
diff --git a/src/datatype.c b/src/datatype.c
index ea73eaf9a691..c9c5a198bd3b 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -505,6 +505,23 @@ const struct datatype xinteger_type = {
.parse = integer_type_parse,
};
+static void queue_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ nft_gmp_print(octx, "queue");
+}
+
+/* Dummy queue_type for set declaration with typeof, see
+ * constant_expr_build_udata and constant_expr_parse_udata,
+ * basetype is used for elements.
+*/
+const struct datatype queue_type = {
+ .type = TYPE_TYPEOF,
+ .name = "queue",
+ .desc = "queue",
+ .basetype = &integer_type,
+ .print = queue_type_print,
+};
+
static void string_type_print(const struct expr *expr, struct output_ctx *octx)
{
unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
diff --git a/src/expression.c b/src/expression.c
index c0cb7f22eb73..62786f483eed 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -371,6 +371,84 @@ struct expr *variable_expr_alloc(const struct location *loc,
return expr;
}
+#define NFTNL_UDATA_CONSTANT_TYPE 0
+#define NFTNL_UDATA_CONSTANT_MAX NFTNL_UDATA_CONSTANT_TYPE
+
+#define CONSTANT_EXPR_NFQUEUE_ID 0
+
+static int constant_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ uint32_t type;
+
+ if (expr->dtype == &queue_type)
+ type = CONSTANT_EXPR_NFQUEUE_ID;
+ else
+ return -1;
+
+ if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_CONSTANT_TYPE, type))
+ return -1;
+
+ return 0;
+}
+
+static int constant_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+ uint32_t value;
+
+ switch (type) {
+ case NFTNL_UDATA_CONSTANT_TYPE:
+ if (len != sizeof(uint32_t))
+ return -1;
+
+ value = nftnl_udata_get_u32(attr);
+ switch (value) {
+ case CONSTANT_EXPR_NFQUEUE_ID:
+ break;
+ default:
+ return -1;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+
+ return 0;
+}
+
+static struct expr *constant_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_CONSTANT_MAX + 1] = {};
+ const struct datatype *dtype = NULL;
+ uint32_t type;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ constant_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_CONSTANT_TYPE])
+ return NULL;
+
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_CONSTANT_TYPE]);
+ switch (type) {
+ case CONSTANT_EXPR_NFQUEUE_ID:
+ dtype = &queue_type;
+ break;
+ default:
+ break;
+ }
+
+ return constant_expr_alloc(&internal_location, dtype, BYTEORDER_HOST_ENDIAN,
+ 16, NULL);
+}
+
static void constant_expr_print(const struct expr *expr,
struct output_ctx *octx)
{
@@ -401,6 +479,8 @@ static const struct expr_ops constant_expr_ops = {
.cmp = constant_expr_cmp,
.clone = constant_expr_clone,
.destroy = constant_expr_destroy,
+ .build_udata = constant_expr_build_udata,
+ .parse_udata = constant_expr_parse_udata,
};
struct expr *constant_expr_alloc(const struct location *loc,
diff --git a/src/json. b/src/json.
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/src/netlink.c b/src/netlink.c
index 25ee3419772b..68e7da68ed68 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1466,7 +1466,11 @@ key_end:
data = netlink_alloc_data(&netlink_location, &nld,
set->data->dtype->type == TYPE_VERDICT ?
NFT_REG_VERDICT : NFT_REG_1);
- datatype_set(data, set->data->dtype);
+
+ if (set->data->dtype->type == TYPE_TYPEOF)
+ datatype_set(data, set->data->dtype->basetype);
+ else
+ datatype_set(data, set->data->dtype);
data->byteorder = set->data->byteorder;
if (set->data->dtype->subtypes) {
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 602fc60e6de3..6e6f3cf8335d 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2173,6 +2173,10 @@ typeof_data_expr : INTERVAL typeof_expr
{
$$ = $1;
}
+ | QUEUE
+ {
+ $$ = constant_expr_alloc(&@$, &queue_type, BYTEORDER_HOST_ENDIAN, 16, NULL);
+ }
;
typeof_expr : primary_expr
diff --git a/tests/shell/testcases/nft-f/dumps/nfqueue.nft b/tests/shell/testcases/nft-f/dumps/nfqueue.nft
new file mode 100644
index 000000000000..7fe3ca669544
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/nfqueue.nft
@@ -0,0 +1,11 @@
+table inet t {
+ map get_queue_id {
+ typeof ip saddr . ip daddr . tcp dport : queue
+ elements = { 127.0.0.1 . 127.0.0.1 . 22 : 1,
+ 127.0.0.1 . 127.0.0.2 . 22 : 2 }
+ }
+
+ chain test {
+ queue flags bypass to ip saddr . ip daddr . tcp dport map @get_queue_id
+ }
+}
diff --git a/tests/shell/testcases/nft-f/nfqueue b/tests/shell/testcases/nft-f/nfqueue
new file mode 100755
index 000000000000..07820b7c4fdd
--- /dev/null
+++ b/tests/shell/testcases/nft-f/nfqueue
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
--
2.30.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH nft] src: allow to map key to nfqueue number
2024-11-06 23:11 ` Pablo Neira Ayuso
@ 2024-11-06 23:34 ` Pablo Neira Ayuso
2024-11-08 12:08 ` Florian Westphal
0 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2024-11-06 23:34 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
[-- Attachment #1: Type: text/plain, Size: 381 bytes --]
On Thu, Nov 07, 2024 at 12:11:53AM +0100, Pablo Neira Ayuso wrote:
> On Wed, Nov 06, 2024 at 05:03:55PM +0100, Pablo Neira Ayuso wrote:
> > I can take a look later today based on your patch, I think I can reuse
> > 90% of it, it is just a subtle detail what I am referring to.
>
> See attachment, not better than your proposal, just a different focus.
Actually, this attachment.
[-- Attachment #2: 0001-src-allow-to-map-key-to-nfqueue-number.patch --]
[-- Type: text/x-diff, Size: 7367 bytes --]
From bf41080edeb3a35e02991ca3ba020a9c79925e12 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Fri, 25 Oct 2024 09:47:25 +0200
Subject: [PATCH] src: allow to map key to nfqueue number
Allow to specify a numeric queue id as part of a map.
The parser side is easy, but the reverse direction (listing) is not.
'queue' is a statement, it doesn't have an expression.
Add a generic 'queue_type' datatype as a shim to the real basetype with
constant expressions, this is used only for udata build/parse, it stores
the "key" (the parser token, here "queue") as udata in kernel and can
then restore the original key.
Add a dumpfile to validate parser & output.
JSON support is missing because JSON allow typeof only since quite
recently.
Joint work with Pablo.
Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1455
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/datatype.h | 4 +-
src/datatype.c | 18 +++++
src/expression.c | 80 +++++++++++++++++++
src/json. | 0
src/netlink.c | 6 +-
src/parser_bison.y | 4 +
tests/shell/testcases/nft-f/dumps/nfqueue.nft | 11 +++
tests/shell/testcases/nft-f/nfqueue | 6 ++
8 files changed, 127 insertions(+), 2 deletions(-)
create mode 100644 src/json.
create mode 100644 tests/shell/testcases/nft-f/dumps/nfqueue.nft
create mode 100755 tests/shell/testcases/nft-f/nfqueue
diff --git a/include/datatype.h b/include/datatype.h
index 75d6d6b8c628..8b950f9165a5 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -140,7 +140,8 @@ struct parse_ctx;
struct datatype {
uint32_t type;
enum byteorder byteorder:8;
- uint32_t alloc:1;
+ uint32_t alloc:1,
+ is_typeof:1;
unsigned int size;
unsigned int subtypes;
const char *name;
@@ -271,6 +272,7 @@ extern const struct datatype boolean_type;
extern const struct datatype priority_type;
extern const struct datatype policy_type;
extern const struct datatype cgroupv2_type;
+extern const struct datatype queue_type;
/* private datatypes for reject statement. */
extern const struct datatype reject_icmp_code_type;
diff --git a/src/datatype.c b/src/datatype.c
index ea73eaf9a691..0c13bbd4270e 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -505,6 +505,24 @@ const struct datatype xinteger_type = {
.parse = integer_type_parse,
};
+static void queue_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ nft_gmp_print(octx, "queue");
+}
+
+/* Dummy queue_type for set declaration with typeof, see
+ * constant_expr_build_udata and constant_expr_parse_udata,
+ * basetype is used for elements.
+*/
+const struct datatype queue_type = {
+ .type = TYPE_INTEGER,
+ .is_typeof = 1,
+ .name = "queue",
+ .desc = "queue",
+ .basetype = &integer_type,
+ .print = queue_type_print,
+};
+
static void string_type_print(const struct expr *expr, struct output_ctx *octx)
{
unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
diff --git a/src/expression.c b/src/expression.c
index c0cb7f22eb73..62786f483eed 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -371,6 +371,84 @@ struct expr *variable_expr_alloc(const struct location *loc,
return expr;
}
+#define NFTNL_UDATA_CONSTANT_TYPE 0
+#define NFTNL_UDATA_CONSTANT_MAX NFTNL_UDATA_CONSTANT_TYPE
+
+#define CONSTANT_EXPR_NFQUEUE_ID 0
+
+static int constant_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ uint32_t type;
+
+ if (expr->dtype == &queue_type)
+ type = CONSTANT_EXPR_NFQUEUE_ID;
+ else
+ return -1;
+
+ if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_CONSTANT_TYPE, type))
+ return -1;
+
+ return 0;
+}
+
+static int constant_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+ uint32_t value;
+
+ switch (type) {
+ case NFTNL_UDATA_CONSTANT_TYPE:
+ if (len != sizeof(uint32_t))
+ return -1;
+
+ value = nftnl_udata_get_u32(attr);
+ switch (value) {
+ case CONSTANT_EXPR_NFQUEUE_ID:
+ break;
+ default:
+ return -1;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+
+ return 0;
+}
+
+static struct expr *constant_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_CONSTANT_MAX + 1] = {};
+ const struct datatype *dtype = NULL;
+ uint32_t type;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ constant_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_CONSTANT_TYPE])
+ return NULL;
+
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_CONSTANT_TYPE]);
+ switch (type) {
+ case CONSTANT_EXPR_NFQUEUE_ID:
+ dtype = &queue_type;
+ break;
+ default:
+ break;
+ }
+
+ return constant_expr_alloc(&internal_location, dtype, BYTEORDER_HOST_ENDIAN,
+ 16, NULL);
+}
+
static void constant_expr_print(const struct expr *expr,
struct output_ctx *octx)
{
@@ -401,6 +479,8 @@ static const struct expr_ops constant_expr_ops = {
.cmp = constant_expr_cmp,
.clone = constant_expr_clone,
.destroy = constant_expr_destroy,
+ .build_udata = constant_expr_build_udata,
+ .parse_udata = constant_expr_parse_udata,
};
struct expr *constant_expr_alloc(const struct location *loc,
diff --git a/src/json. b/src/json.
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/src/netlink.c b/src/netlink.c
index 25ee3419772b..36140fb63d6f 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1466,7 +1466,11 @@ key_end:
data = netlink_alloc_data(&netlink_location, &nld,
set->data->dtype->type == TYPE_VERDICT ?
NFT_REG_VERDICT : NFT_REG_1);
- datatype_set(data, set->data->dtype);
+
+ if (set->data->dtype->is_typeof)
+ datatype_set(data, set->data->dtype->basetype);
+ else
+ datatype_set(data, set->data->dtype);
data->byteorder = set->data->byteorder;
if (set->data->dtype->subtypes) {
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 602fc60e6de3..6e6f3cf8335d 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2173,6 +2173,10 @@ typeof_data_expr : INTERVAL typeof_expr
{
$$ = $1;
}
+ | QUEUE
+ {
+ $$ = constant_expr_alloc(&@$, &queue_type, BYTEORDER_HOST_ENDIAN, 16, NULL);
+ }
;
typeof_expr : primary_expr
diff --git a/tests/shell/testcases/nft-f/dumps/nfqueue.nft b/tests/shell/testcases/nft-f/dumps/nfqueue.nft
new file mode 100644
index 000000000000..7fe3ca669544
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/nfqueue.nft
@@ -0,0 +1,11 @@
+table inet t {
+ map get_queue_id {
+ typeof ip saddr . ip daddr . tcp dport : queue
+ elements = { 127.0.0.1 . 127.0.0.1 . 22 : 1,
+ 127.0.0.1 . 127.0.0.2 . 22 : 2 }
+ }
+
+ chain test {
+ queue flags bypass to ip saddr . ip daddr . tcp dport map @get_queue_id
+ }
+}
diff --git a/tests/shell/testcases/nft-f/nfqueue b/tests/shell/testcases/nft-f/nfqueue
new file mode 100755
index 000000000000..07820b7c4fdd
--- /dev/null
+++ b/tests/shell/testcases/nft-f/nfqueue
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
--
2.30.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH nft] src: allow to map key to nfqueue number
2024-11-06 23:34 ` Pablo Neira Ayuso
@ 2024-11-08 12:08 ` Florian Westphal
2024-11-11 10:38 ` Pablo Neira Ayuso
0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2024-11-08 12:08 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Thu, Nov 07, 2024 at 12:11:53AM +0100, Pablo Neira Ayuso wrote:
> > On Wed, Nov 06, 2024 at 05:03:55PM +0100, Pablo Neira Ayuso wrote:
> > > I can take a look later today based on your patch, I think I can reuse
> > > 90% of it, it is just a subtle detail what I am referring to.
> >
> > See attachment, not better than your proposal, just a different focus.
>
> Actually, this attachment.
Just apply this.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH nft] src: allow to map key to nfqueue number
2024-11-08 12:08 ` Florian Westphal
@ 2024-11-11 10:38 ` Pablo Neira Ayuso
0 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2024-11-11 10:38 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Fri, Nov 08, 2024 at 01:08:54PM +0100, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > On Thu, Nov 07, 2024 at 12:11:53AM +0100, Pablo Neira Ayuso wrote:
> > > On Wed, Nov 06, 2024 at 05:03:55PM +0100, Pablo Neira Ayuso wrote:
> > > > I can take a look later today based on your patch, I think I can reuse
> > > > 90% of it, it is just a subtle detail what I am referring to.
> > >
> > > See attachment, not better than your proposal, just a different focus.
> >
> > Actually, this attachment.
>
> Just apply this.
Done.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-11-11 10:38 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-25 7:47 [PATCH nft] src: allow to map key to nfqueue number Florian Westphal
2024-11-06 13:28 ` Pablo Neira Ayuso
2024-11-06 13:52 ` Florian Westphal
2024-11-06 14:32 ` Florian Westphal
2024-11-06 16:03 ` Pablo Neira Ayuso
2024-11-06 23:11 ` Pablo Neira Ayuso
2024-11-06 23:34 ` Pablo Neira Ayuso
2024-11-08 12:08 ` Florian Westphal
2024-11-11 10:38 ` Pablo Neira Ayuso
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox