* [PATCH nft 0/3] nftables: add typeof support for objref maps
@ 2024-02-29 10:41 Florian Westphal
2024-02-29 10:41 ` [PATCH nft 1/3] parser: allow typeof in " Florian Westphal
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Florian Westphal @ 2024-02-29 10:41 UTC (permalink / raw)
To: netfilter-devel
First patch extends the bison parser to permit typeof with objref maps.
Second patch "fixes" nftables listing mode to keep the typeof
information for objref maps rather than doing a fallback to 'type'.
Third patch adds a test case for this.
These patches are on top of the two bison parser compaction changes.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH nft 1/3] parser: allow typeof in objref maps
2024-02-29 10:41 [PATCH nft 0/3] nftables: add typeof support for objref maps Florian Westphal
@ 2024-02-29 10:41 ` Florian Westphal
2024-02-29 10:41 ` [PATCH nft 2/3] netlink: allow typeof keywords with objref maps during listing Florian Westphal
2024-02-29 10:41 ` [PATCH nft 3/3] tests: maps: add a test case for "limit" objref map Florian Westphal
2 siblings, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2024-02-29 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Its currently not possible to declare a map that
stores object references with the "typeof" keyword, e.g.
map m {
type ipv4_addr : limit
will work, but
map m {
typeof ip saddr : limit
will give a syntax error ("unexpected limit").
Followup pach will add support for listing side too.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/parser_bison.y | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index cba37c686f66..cd1dc658882d 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2340,6 +2340,15 @@ map_block : /* empty */ { $$ = $<set>-1; }
$1->flags |= NFT_SET_OBJECT;
$$ = $1;
}
+ | map_block TYPEOF
+ typeof_expr COLON map_block_obj_type
+ stmt_separator
+ {
+ $1->key = $3;
+ $1->objtype = $5;
+ $1->flags |= NFT_SET_OBJECT;
+ $$ = $1;
+ }
| map_block FLAGS set_flag_list stmt_separator
{
$1->flags |= $3;
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH nft 2/3] netlink: allow typeof keywords with objref maps during listing
2024-02-29 10:41 [PATCH nft 0/3] nftables: add typeof support for objref maps Florian Westphal
2024-02-29 10:41 ` [PATCH nft 1/3] parser: allow typeof in " Florian Westphal
@ 2024-02-29 10:41 ` Florian Westphal
2024-02-29 10:41 ` [PATCH nft 3/3] tests: maps: add a test case for "limit" objref map Florian Westphal
2 siblings, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2024-02-29 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Without this,
typeof meta l4proto . ip saddr . tcp sport : limit
... is shown as
type inet_proto . ipv4_addr . inet_service : limit
The "data" element is a value (the object type number).
It doesn't support userinfo data.
There is no reason to add it, the value is the object type
number that the object-reference map stores.
So, if we have an objref map, DO NOT discard the key part,
as we do for normal maps.
For normal maps, we support either typeof notation, i.e.:
typeof meta l4proto . ip saddr . tcp sport : ip saddr
or the data type version:
type inet_proto . ipv4_addr . inet_service : ipv4_addr
... but not a mix, a hyptothetical
typeof meta l4proto . ip saddr . tcp sport : ipv4_addr
... does not work.
If nft finds no udata attached to the data element, for normal
map case, it has to fall back to the "type" form.
But for objref maps this is expected, udata for key but not for data.
Hence, for objref case, keep the typeof part if its valid.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/netlink.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/netlink.c b/src/netlink.c
index 3d685b575e64..0088b742d573 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1044,6 +1044,8 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
}
list_splice_tail(&set_parse_ctx.stmt_list, &set->stmt_list);
+ set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
+
if (datatype) {
uint32_t dlen;
@@ -1056,6 +1058,11 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
typeof_expr_data->len = klen;
set->data = typeof_expr_data;
typeof_expr_data = NULL;
+ } else if (set->flags & NFT_SET_OBJECT) {
+ set->data = constant_expr_alloc(&netlink_location,
+ dtype2,
+ databyteorder, klen,
+ NULL);
} else {
set->data = constant_expr_alloc(&netlink_location,
dtype2,
@@ -1084,7 +1091,6 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
NULL);
}
- set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE);
set->objtype = objtype;
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH nft 3/3] tests: maps: add a test case for "limit" objref map
2024-02-29 10:41 [PATCH nft 0/3] nftables: add typeof support for objref maps Florian Westphal
2024-02-29 10:41 ` [PATCH nft 1/3] parser: allow typeof in " Florian Westphal
2024-02-29 10:41 ` [PATCH nft 2/3] netlink: allow typeof keywords with objref maps during listing Florian Westphal
@ 2024-02-29 10:41 ` Florian Westphal
2 siblings, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2024-02-29 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
check add, delete and removal operations for objref maps.
Also check type vs. typeof declarations and use both
interval and interval+concatenation (rbtree, pipapo).
Signed-off-by: Florian Westphal <fw@strlen.de>
---
.../maps/dumps/named_limits.json-nft | 328 ++++++++++++++++++
.../testcases/maps/dumps/named_limits.nft | 55 +++
tests/shell/testcases/maps/named_limits | 59 ++++
3 files changed, 442 insertions(+)
create mode 100644 tests/shell/testcases/maps/dumps/named_limits.json-nft
create mode 100644 tests/shell/testcases/maps/dumps/named_limits.nft
create mode 100755 tests/shell/testcases/maps/named_limits
diff --git a/tests/shell/testcases/maps/dumps/named_limits.json-nft b/tests/shell/testcases/maps/dumps/named_limits.json-nft
new file mode 100644
index 000000000000..28a92529c8d2
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/named_limits.json-nft
@@ -0,0 +1,328 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "tarpit-pps",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "burst": 5
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "tarpit-bps",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "rate_unit": "kbytes"
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "http-bulk-rl-1m",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "rate_unit": "mbytes"
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "http-bulk-rl-10m",
+ "table": "filter",
+ "handle": 0,
+ "rate": 10,
+ "per": "second",
+ "rate_unit": "mbytes"
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "tarpit4",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 10000,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "timeout": 60
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "tarpit6",
+ "table": "filter",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "size": 10000,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "timeout": 60
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "addr4limit",
+ "table": "filter",
+ "type": [
+ "inet_proto",
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "map": "limit",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 16
+ }
+ },
+ {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ ]
+ },
+ "tarpit-bps"
+ ],
+ [
+ {
+ "concat": [
+ "udp",
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 16
+ }
+ },
+ {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ ]
+ },
+ "tarpit-pps"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ "127.0.0.1",
+ "127.1.2.3"
+ ]
+ },
+ {
+ "range": [
+ 1,
+ 1024
+ ]
+ }
+ ]
+ },
+ "tarpit-pps"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ "10.0.0.1",
+ "10.0.0.255"
+ ]
+ },
+ 80
+ ]
+ },
+ "http-bulk-rl-1m"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ "10.0.0.1",
+ "10.0.0.255"
+ ]
+ },
+ 443
+ ]
+ },
+ "http-bulk-rl-1m"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "prefix": {
+ "addr": "10.0.1.0",
+ "len": 24
+ }
+ },
+ {
+ "range": [
+ 1024,
+ 65535
+ ]
+ }
+ ]
+ },
+ "http-bulk-rl-10m"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ "10.0.2.1",
+ 22
+ ]
+ },
+ "http-bulk-rl-10m"
+ ]
+ ]
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "saddr6limit",
+ "table": "filter",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "map": "limit",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "range": [
+ "dead::beef",
+ "dead::1:aced"
+ ]
+ },
+ "tarpit-pps"
+ ]
+ ]
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "limit": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "th",
+ "field": "sport"
+ }
+ }
+ ]
+ },
+ "data": "@addr4limit"
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "limit": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "saddr"
+ }
+ },
+ "data": "@saddr6limit"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/named_limits.nft b/tests/shell/testcases/maps/dumps/named_limits.nft
new file mode 100644
index 000000000000..214df204b770
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/named_limits.nft
@@ -0,0 +1,55 @@
+table inet filter {
+ limit tarpit-pps {
+ rate 1/second
+ }
+
+ limit tarpit-bps {
+ rate 1 kbytes/second
+ }
+
+ limit http-bulk-rl-1m {
+ rate 1 mbytes/second
+ }
+
+ limit http-bulk-rl-10m {
+ rate 10 mbytes/second
+ }
+
+ set tarpit4 {
+ typeof ip saddr
+ size 10000
+ flags dynamic,timeout
+ timeout 1m
+ }
+
+ set tarpit6 {
+ typeof ip6 saddr
+ size 10000
+ flags dynamic,timeout
+ timeout 1m
+ }
+
+ map addr4limit {
+ typeof meta l4proto . ip saddr . tcp sport : limit
+ flags interval
+ elements = { tcp . 192.168.0.0/16 . 1-65535 : "tarpit-bps",
+ udp . 192.168.0.0/16 . 1-65535 : "tarpit-pps",
+ tcp . 127.0.0.1-127.1.2.3 . 1-1024 : "tarpit-pps",
+ tcp . 10.0.0.1-10.0.0.255 . 80 : "http-bulk-rl-1m",
+ tcp . 10.0.0.1-10.0.0.255 . 443 : "http-bulk-rl-1m",
+ tcp . 10.0.1.0/24 . 1024-65535 : "http-bulk-rl-10m",
+ tcp . 10.0.2.1 . 22 : "http-bulk-rl-10m" }
+ }
+
+ map saddr6limit {
+ typeof ip6 saddr : limit
+ flags interval
+ elements = { dead::beef-dead::1:aced : "tarpit-pps" }
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ limit name meta l4proto . ip saddr . th sport map @addr4limit
+ limit name ip6 saddr map @saddr6limit
+ }
+}
diff --git a/tests/shell/testcases/maps/named_limits b/tests/shell/testcases/maps/named_limits
new file mode 100755
index 000000000000..5604f6caeda6
--- /dev/null
+++ b/tests/shell/testcases/maps/named_limits
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile" || exit 1
+
+add_add_then_create()
+{
+ cmd="$@"
+
+ $NFT "add element inet filter $cmd" || exit 2
+
+ # again, kernel should suppress -EEXIST
+ $NFT "add element inet filter $cmd" || exit 3
+
+ # AGAIN, kernel should report -EEXIST
+ $NFT "create element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 4
+}
+
+add_create_dupe()
+{
+ cmd="$@"
+
+ $NFT "add element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 10
+ $NFT "create element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 11
+}
+
+delete()
+{
+ cmd="$@"
+
+ $NFT "delete element inet filter $cmd" || exit 30
+ $NFT "delete element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 31
+
+ # destroy should NOT report an error
+# $NFT "destroy element inet filter $cmd" || exit 40
+}
+
+add_add_then_create 'saddr6limit { fee1::dead : "tarpit-pps" }'
+add_add_then_create 'saddr6limit { c01a::/64 : "tarpit-bps" }'
+
+# test same with a diffent set type (concat + interval)
+add_add_then_create 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "tarpit-pps" }'
+
+# now test duplicate key with *DIFFERENT* limiter, should fail
+add_create_dupe 'saddr6limit { fee1::dead : "tarpit-bps" }'
+
+add_create_dupe 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "http-bulk-rl-10m" }'
+add_create_dupe 'addr4limit { udp . 1.2.3.4 . 43 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "http-bulk-rl-10m" }'
+add_create_dupe 'addr4limit { udp . 1.2.3.5 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "http-bulk-rl-10m" }'
+add_create_dupe 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-bps", tcp . 1.2.3.4 . 42 : "tarpit-pps" }'
+
+# delete keys again
+delete 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 :"tarpit-pps" }'
+
+delete 'saddr6limit { fee1::dead : "tarpit-pps" }'
+delete 'saddr6limit { c01a::/64 : "tarpit-bps" }'
+
+exit 0
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-02-29 10:45 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-29 10:41 [PATCH nft 0/3] nftables: add typeof support for objref maps Florian Westphal
2024-02-29 10:41 ` [PATCH nft 1/3] parser: allow typeof in " Florian Westphal
2024-02-29 10:41 ` [PATCH nft 2/3] netlink: allow typeof keywords with objref maps during listing Florian Westphal
2024-02-29 10:41 ` [PATCH nft 3/3] tests: maps: add a test case for "limit" objref map Florian Westphal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).