* [nft PATCH v5 0/3] Support wildcard netdev hooks
@ 2025-07-31 22:29 Phil Sutter
2025-07-31 22:29 ` [nft PATCH v5 1/3] mnl: Support simple wildcards in " Phil Sutter
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Phil Sutter @ 2025-07-31 22:29 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Changes since v4:
- Adjust code to NFTA_HOOK_PREFIX attribute
Changes since v3:
- Unrelated patch 1 pushed out separately
- Fixed variable types and function prefix in patch 1
- Document interface wildcard support in nft.8
Changes since v2:
- New patch 1 fixing for excessive mnl_attr_nest_end() calls
- Introduce a helper function in patch 2 which also sanity-checks an
array index - this is a copy of libnftnl's function for the same
purpose, but we rather get rid of the dupicated calling code instead
of exposing (and thus maintaining in future) the function from
libnftnl
This is the remaining needed code change to support wildcard hook specs.
Patch 3 also adds shell test cases to cover the functionality. The
flowtable variant is skipped if 'nft list hooks' does not provide
flowtable information as this requires NFNL_HOOK_TYPE_NFT_FLOWTABLE in
kernel.
Phil Sutter (3):
mnl: Support simple wildcards in netdev hooks
parser_bison: Accept ASTERISK_STRING in flowtable_expr_member
tests: shell: Test ifname-based hooks
doc/nft.txt | 30 +++++++++++--
include/linux/netfilter/nf_tables.h | 2 +
src/mnl.c | 26 +++++++++--
src/parser_bison.y | 11 +----
.../features/list_hooks_flowtable_info.sh | 7 +++
.../netdev_chain_name_based_hook_0.json-nft | 34 ++++++++++++++
.../dumps/netdev_chain_name_based_hook_0.nft | 5 +++
.../chains/netdev_chain_name_based_hook_0 | 44 ++++++++++++++++++
.../testcases/flowtable/0016name_based_hook_0 | 45 +++++++++++++++++++
.../dumps/0016name_based_hook_0.json-nft | 32 +++++++++++++
.../flowtable/dumps/0016name_based_hook_0.nft | 6 +++
11 files changed, 225 insertions(+), 17 deletions(-)
create mode 100755 tests/shell/features/list_hooks_flowtable_info.sh
create mode 100644 tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.json-nft
create mode 100644 tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.nft
create mode 100755 tests/shell/testcases/chains/netdev_chain_name_based_hook_0
create mode 100755 tests/shell/testcases/flowtable/0016name_based_hook_0
create mode 100644 tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.json-nft
create mode 100644 tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.nft
--
2.49.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [nft PATCH v5 1/3] mnl: Support simple wildcards in netdev hooks
2025-07-31 22:29 [nft PATCH v5 0/3] Support wildcard netdev hooks Phil Sutter
@ 2025-07-31 22:29 ` Phil Sutter
2025-09-04 15:16 ` Pablo Neira Ayuso
2025-07-31 22:29 ` [nft PATCH v5 2/3] parser_bison: Accept ASTERISK_STRING in flowtable_expr_member Phil Sutter
2025-07-31 22:29 ` [nft PATCH v5 3/3] tests: shell: Test ifname-based hooks Phil Sutter
2 siblings, 1 reply; 10+ messages in thread
From: Phil Sutter @ 2025-07-31 22:29 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
When building NFTA_{FLOWTABLE_,}HOOK_DEVS attributes, detect trailing
asterisks in interface names and transmit the leading part in a
NFTA_DEVICE_PREFIX attribute.
Deserialization (i.e., appending asterisk to interface prefixes returned
in NFTA_DEVICE_PREFIX atributes happens in libnftnl.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
Changes since v4:
- Introduce and use NFTA_DEVICE_PREFIX which contains a NUL-terminated
string as well but signals the kernel to interpret it as a prefix to
match interfaces on.
- Do not send wildcards in NFTA_HOOK_DEV: On one hand, the kernel can't
detect them anymore since they are NUL-terminated as well. On the
other, it would defeat the purpose of having NFTA_DEVICE_PREFIX, which
is to not crash old user space.
Changes since v3:
- Use uint16_t for 'attr' parameter and size_t for 'len' variable
- Use mnl_nft_ prefix for the helper function
Changes since v2:
- Introduce mnl_attr_put_ifname() to perform the conditional
mnl_attr_put() parameter adjustment
- Sanity-check array index in above function to avoid out-of-bounds
access
---
include/linux/netfilter/nf_tables.h | 2 ++
src/mnl.c | 26 +++++++++++++++++++++++---
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index f57963e89fd16..b38d4780ae8c8 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1774,10 +1774,12 @@ enum nft_synproxy_attributes {
* enum nft_device_attributes - nf_tables device netlink attributes
*
* @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
+ * @NFTA_DEVICE_PREFIX: device name prefix, a simple wildcard (NLA_STRING)
*/
enum nft_devices_attributes {
NFTA_DEVICE_UNSPEC,
NFTA_DEVICE_NAME,
+ NFTA_DEVICE_PREFIX,
__NFTA_DEVICE_MAX
};
#define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
diff --git a/src/mnl.c b/src/mnl.c
index 43229f2498e55..b532b8ff00c1e 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -795,6 +795,26 @@ static void nft_dev_array_free(const struct nft_dev *dev_array)
free_const(dev_array);
}
+static bool is_wildcard_str(const char *str)
+{
+ size_t len = strlen(str);
+
+ if (len < 1 || str[len - 1] != '*')
+ return false;
+ if (len < 2 || str[len - 2] != '\\')
+ return true;
+ /* XXX: ignore backslash escaping for now */
+ return false;
+}
+
+static void mnl_nft_attr_put_ifname(struct nlmsghdr *nlh, const char *ifname)
+{
+ uint16_t attr = is_wildcard_str(ifname) ?
+ NFTA_DEVICE_PREFIX : NFTA_DEVICE_NAME;
+
+ mnl_attr_put_strz(nlh, attr, ifname);
+}
+
static void mnl_nft_chain_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
{
const struct expr *dev_expr = cmd->chain->dev_expr;
@@ -803,14 +823,14 @@ static void mnl_nft_chain_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
int i, num_devs = 0;
dev_array = nft_dev_array(dev_expr, &num_devs);
- if (num_devs == 1) {
+ if (num_devs == 1 && !is_wildcard_str(dev_array[0].ifname)) {
cmd_add_loc(cmd, nlh, dev_array[0].location);
mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, dev_array[0].ifname);
} else {
nest_dev = mnl_attr_nest_start(nlh, NFTA_HOOK_DEVS);
for (i = 0; i < num_devs; i++) {
cmd_add_loc(cmd, nlh, dev_array[i].location);
- mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname);
+ mnl_nft_attr_put_ifname(nlh, dev_array[i].ifname);
}
mnl_attr_nest_end(nlh, nest_dev);
}
@@ -2091,7 +2111,7 @@ static void mnl_nft_ft_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS);
for (i = 0; i < num_devs; i++) {
cmd_add_loc(cmd, nlh, dev_array[i].location);
- mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname);
+ mnl_nft_attr_put_ifname(nlh, dev_array[i].ifname);
}
mnl_attr_nest_end(nlh, nest_dev);
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [nft PATCH v5 2/3] parser_bison: Accept ASTERISK_STRING in flowtable_expr_member
2025-07-31 22:29 [nft PATCH v5 0/3] Support wildcard netdev hooks Phil Sutter
2025-07-31 22:29 ` [nft PATCH v5 1/3] mnl: Support simple wildcards in " Phil Sutter
@ 2025-07-31 22:29 ` Phil Sutter
2025-09-04 15:20 ` Pablo Neira Ayuso
2025-07-31 22:29 ` [nft PATCH v5 3/3] tests: shell: Test ifname-based hooks Phil Sutter
2 siblings, 1 reply; 10+ messages in thread
From: Phil Sutter @ 2025-07-31 22:29 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
All clauses are identical, so instead of adding a third one for
ASTERISK_STRING, use a single one for 'string' (which combines all three
variants).
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
Changes since v3:
- Cover interface wildcards in nft.8
---
doc/nft.txt | 30 ++++++++++++++++++++++++++----
src/parser_bison.y | 11 +----------
2 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/doc/nft.txt b/doc/nft.txt
index 8712981943d78..42cdd38a27b67 100644
--- a/doc/nft.txt
+++ b/doc/nft.txt
@@ -387,13 +387,19 @@ add table inet mytable
CHAINS
------
[verse]
-{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' [*device* 'device'] *priority* 'priority' *;* [*policy* 'policy' *;*] [*comment* 'comment' *;*] *}*]
+____
+{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' ['DEVICE'] *priority* 'priority' *;* [*policy* 'policy' *;*] [*comment* 'comment' *;*] *}*]
{*delete* | *destroy* | *list* | *flush*} *chain* ['family'] 'table' 'chain'
*list chains* ['family']
*delete chain* ['family'] 'table' *handle* 'handle'
*destroy chain* ['family'] 'table' *handle* 'handle'
*rename chain* ['family'] 'table' 'chain' 'newname'
+'DEVICE' := {*device* 'DEVICE_NAME' | *devices = {* 'DEVICE_LIST' *}*}
+'DEVICE_LIST' := 'DEVICE_NAME' [*,* 'DEVICE_LIST']
+'DEVICE_NAME' := 'string' | 'string'***
+____
+
Chains are containers for rules. They exist in two kinds, base chains and
regular chains. A base chain is an entry point for packets from the networking
stack, a regular chain may be used as jump target and is used for better rule
@@ -436,7 +442,7 @@ Apart from the special cases illustrated above (e.g. *nat* type not supporting
* The netdev family supports merely two combinations, namely *filter* type with
*ingress* hook and *filter* type with *egress* hook. Base chains in this
- family also require the *device* parameter to be present since they exist per
+ family also require the 'DEVICE' parameter to be present since they exist per
interface only.
* The arp family supports only the *input* and *output* hooks, both in chains of type
*filter*.
@@ -449,7 +455,13 @@ Apart from the special cases illustrated above (e.g. *nat* type not supporting
The *device* parameter accepts a network interface name as a string, and is
required when adding a base chain that filters traffic on the ingress or
egress hooks. Any ingress or egress chains will only filter traffic from the
-interface specified in the *device* parameter.
+interface specified in the *device* parameter. The same base chain may be used
+for multiple devices by using the *devices* parameter instead.
+
+With newer kernels there is also basic support for wildcards in 'DEVICE_NAME'
+by specifying an asterisk suffix. The chain will apply to all interfaces
+matching the given prefix. Use the *list hooks* command to see the current
+status.
The *priority* parameter accepts a signed integer value or a standard priority
name which specifies the order in which chains with the same *hook* value are
@@ -763,11 +775,16 @@ per element comment field
FLOWTABLES
-----------
[verse]
-{*add* | *create*} *flowtable* ['family'] 'table' 'flowtable' *{ hook* 'hook' *priority* 'priority' *; devices = {* 'device'[*,* ...] *} ; }*
+____
+{*add* | *create*} *flowtable* ['family'] 'table' 'flowtable' *{ hook* 'hook' *priority* 'priority' *; devices = {* 'DEVICE_LIST' *} ; }*
*list flowtables* ['family'] ['table']
{*delete* | *destroy* | *list*} *flowtable* ['family'] 'table' 'flowtable'
*delete* *flowtable* ['family'] 'table' *handle* 'handle'
+'DEVICE_LIST' := 'DEVICE_NAME' [*,* 'DEVICE_LIST']
+'DEVICE_NAME' := 'string' | 'string'***
+____
+
Flowtables allow you to accelerate packet forwarding in software. Flowtables
entries are represented through a tuple that is composed of the input interface,
source and destination address, source and destination port; and layer 3/4
@@ -786,6 +803,11 @@ The *priority* can be a signed integer or *filter* which stands for 0. Addition
and subtraction can be used to set relative priority, e.g. filter + 5 equals to
5.
+With newer kernels there is basic support for wildcards in 'DEVICE_LIST' by
+specifying an asterisk suffix. The flowtable will apply to all interfaces
+matching the given prefix. Use the *list hooks* command to see the current
+status.
+
[horizontal]
*add*:: Add a new flowtable for the given family with the given name.
*delete*:: Delete the specified flowtable.
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 0b1ea699c6102..d665f2fa8c7c1 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2473,16 +2473,7 @@ flowtable_list_expr : flowtable_expr_member
| flowtable_list_expr COMMA opt_newline
;
-flowtable_expr_member : QUOTED_STRING
- {
- struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1);
-
- if (!expr)
- YYERROR;
-
- $$ = expr;
- }
- | STRING
+flowtable_expr_member : string
{
struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1);
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [nft PATCH v5 3/3] tests: shell: Test ifname-based hooks
2025-07-31 22:29 [nft PATCH v5 0/3] Support wildcard netdev hooks Phil Sutter
2025-07-31 22:29 ` [nft PATCH v5 1/3] mnl: Support simple wildcards in " Phil Sutter
2025-07-31 22:29 ` [nft PATCH v5 2/3] parser_bison: Accept ASTERISK_STRING in flowtable_expr_member Phil Sutter
@ 2025-07-31 22:29 ` Phil Sutter
2 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-07-31 22:29 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Assert that:
- Non-matching interface specs are accepted
- Existing interfaces are hooked into upon flowtable/chain creation
- A new device matching the spec is hooked into immediately
- No stale hooks remain in 'nft list hooks' output
- Wildcard hooks basically work
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
.../features/list_hooks_flowtable_info.sh | 7 +++
.../netdev_chain_name_based_hook_0.json-nft | 34 ++++++++++++++
.../dumps/netdev_chain_name_based_hook_0.nft | 5 +++
.../chains/netdev_chain_name_based_hook_0 | 44 ++++++++++++++++++
.../testcases/flowtable/0016name_based_hook_0 | 45 +++++++++++++++++++
.../dumps/0016name_based_hook_0.json-nft | 32 +++++++++++++
.../flowtable/dumps/0016name_based_hook_0.nft | 6 +++
7 files changed, 173 insertions(+)
create mode 100755 tests/shell/features/list_hooks_flowtable_info.sh
create mode 100644 tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.json-nft
create mode 100644 tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.nft
create mode 100755 tests/shell/testcases/chains/netdev_chain_name_based_hook_0
create mode 100755 tests/shell/testcases/flowtable/0016name_based_hook_0
create mode 100644 tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.json-nft
create mode 100644 tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.nft
diff --git a/tests/shell/features/list_hooks_flowtable_info.sh b/tests/shell/features/list_hooks_flowtable_info.sh
new file mode 100755
index 0000000000000..58bc57e040959
--- /dev/null
+++ b/tests/shell/features/list_hooks_flowtable_info.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# check for flowtable info in 'list hooks' output
+
+unshare -n bash -c " \
+$NFT \"table inet t { flowtable ft { hook ingress priority 0; devices = { lo }; }; }\"; \
+$NFT list hooks netdev device lo | grep -q flowtable\ inet\ t\ ft"
diff --git a/tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.json-nft b/tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.json-nft
new file mode 100644
index 0000000000000..00706271e96a4
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.json-nft
@@ -0,0 +1,34 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "dev": [
+ "foo*",
+ "lo"
+ ],
+ "type": "filter",
+ "hook": "ingress",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.nft b/tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.nft
new file mode 100644
index 0000000000000..ac5acacd12e6d
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_chain_name_based_hook_0.nft
@@ -0,0 +1,5 @@
+table netdev t {
+ chain c {
+ type filter hook ingress devices = { "foo*", "lo" } priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/netdev_chain_name_based_hook_0 b/tests/shell/testcases/chains/netdev_chain_name_based_hook_0
new file mode 100755
index 0000000000000..8a8a601784084
--- /dev/null
+++ b/tests/shell/testcases/chains/netdev_chain_name_based_hook_0
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_ifname_based_hooks)
+
+cspec=' chain netdev t c '
+$NFT add table netdev t
+$NFT add $cspec '{ type filter hook ingress priority 0; devices = { lo, foo* }; }'
+$NFT list hooks netdev device lo | grep -q "$cspec" || {
+ echo "Existing device lo not hooked into chain as expected"
+ exit 1
+}
+
+[[ $($NFT list hooks | grep -c "$cspec") -eq 1 ]] || {
+ echo "Chain hooks into more than just lo"
+ exit 2
+}
+
+ip link add foo1 type dummy
+$NFT list hooks netdev device foo1 | grep -q "$cspec" || {
+ echo "Chain did not hook into new device foo1"
+ exit 3
+}
+[[ $($NFT list hooks | grep -c "$cspec") -eq 2 ]] || {
+ echo "Chain expected to hook into exactly two devices"
+ exit 4
+}
+
+ip link del foo1
+$NFT list hooks netdev device foo1 | grep -q "$cspec" && {
+ echo "Chain still hooks into removed device foo1"
+ exit 5
+}
+[[ $($NFT list hooks | grep -c "$cspec") -eq 1 ]] || {
+ echo "Chain expected to hook into just lo"
+ exit 6
+}
+
+for ((i = 0; i < 100; i++)); do
+ ip link add foo$i type dummy
+done
+[[ $($NFT list hooks | grep -c "$cspec") -eq 101 ]] || {
+ echo "Chain did not hook into all 100 new devices"
+ exit 7
+}
diff --git a/tests/shell/testcases/flowtable/0016name_based_hook_0 b/tests/shell/testcases/flowtable/0016name_based_hook_0
new file mode 100755
index 0000000000000..9a55596027158
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0016name_based_hook_0
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_ifname_based_hooks)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_list_hooks_flowtable_info)
+
+ftspec=' flowtable ip t ft '
+$NFT add table t
+$NFT add $ftspec '{ hook ingress priority 0; devices = { lo, foo* }; }'
+$NFT list hooks netdev device lo | grep -q "$ftspec" || {
+ echo "Existing device lo not hooked into flowtable as expected"
+ exit 1
+}
+
+[[ $($NFT list hooks | grep -c "$ftspec") -eq 1 ]] || {
+ echo "Flowtable hooks into more than just lo"
+ exit 2
+}
+
+ip link add foo1 type dummy
+$NFT list hooks netdev device foo1 | grep -q "$ftspec" || {
+ echo "Flowtable did not hook into new device foo1"
+ exit 3
+}
+[[ $($NFT list hooks | grep -c "$ftspec") -eq 2 ]] || {
+ echo "Flowtable expected to hook into exactly two devices"
+ exit 4
+}
+
+ip link del foo1
+$NFT list hooks netdev device foo1 | grep -q "$ftspec" && {
+ echo "Flowtable still hooks into removed device foo1"
+ exit 5
+}
+[[ $($NFT list hooks | grep -c "$ftspec") -eq 1 ]] || {
+ echo "Flowtable expected to hook into just lo"
+ exit 6
+}
+
+for ((i = 0; i < 100; i++)); do
+ ip link add foo$i type dummy
+done
+[[ $($NFT list hooks | grep -c "$ftspec") -eq 101 ]] || {
+ echo "Flowtable did not hook into all 100 new devices"
+ exit 7
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.json-nft b/tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.json-nft
new file mode 100644
index 0000000000000..93e263323ff95
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.json-nft
@@ -0,0 +1,32 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "ip",
+ "name": "ft",
+ "table": "t",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 0,
+ "dev": [
+ "foo*",
+ "lo"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.nft b/tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.nft
new file mode 100644
index 0000000000000..b4810664a956f
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0016name_based_hook_0.nft
@@ -0,0 +1,6 @@
+table ip t {
+ flowtable ft {
+ hook ingress priority filter
+ devices = { "foo*", "lo" }
+ }
+}
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [nft PATCH v5 1/3] mnl: Support simple wildcards in netdev hooks
2025-07-31 22:29 ` [nft PATCH v5 1/3] mnl: Support simple wildcards in " Phil Sutter
@ 2025-09-04 15:16 ` Pablo Neira Ayuso
2025-09-04 22:27 ` Phil Sutter
0 siblings, 1 reply; 10+ messages in thread
From: Pablo Neira Ayuso @ 2025-09-04 15:16 UTC (permalink / raw)
To: Phil Sutter; +Cc: netfilter-devel
Hi Phil,
NFTA_DEVICE_PREFIX is now available in net.git, let's pick up on this.
On Fri, Aug 01, 2025 at 12:29:43AM +0200, Phil Sutter wrote:
> When building NFTA_{FLOWTABLE_,}HOOK_DEVS attributes, detect trailing
> asterisks in interface names and transmit the leading part in a
> NFTA_DEVICE_PREFIX attribute.
>
> Deserialization (i.e., appending asterisk to interface prefixes returned
> in NFTA_DEVICE_PREFIX atributes happens in libnftnl.
>
> Signed-off-by: Phil Sutter <phil@nwl.cc>
> ---
> Changes since v4:
> - Introduce and use NFTA_DEVICE_PREFIX which contains a NUL-terminated
> string as well but signals the kernel to interpret it as a prefix to
> match interfaces on.
> - Do not send wildcards in NFTA_HOOK_DEV: On one hand, the kernel can't
> detect them anymore since they are NUL-terminated as well. On the
> other, it would defeat the purpose of having NFTA_DEVICE_PREFIX, which
> is to not crash old user space.
>
> Changes since v3:
> - Use uint16_t for 'attr' parameter and size_t for 'len' variable
> - Use mnl_nft_ prefix for the helper function
>
> Changes since v2:
> - Introduce mnl_attr_put_ifname() to perform the conditional
> mnl_attr_put() parameter adjustment
> - Sanity-check array index in above function to avoid out-of-bounds
> access
> ---
> include/linux/netfilter/nf_tables.h | 2 ++
> src/mnl.c | 26 +++++++++++++++++++++++---
> 2 files changed, 25 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
> index f57963e89fd16..b38d4780ae8c8 100644
> --- a/include/linux/netfilter/nf_tables.h
> +++ b/include/linux/netfilter/nf_tables.h
> @@ -1774,10 +1774,12 @@ enum nft_synproxy_attributes {
> * enum nft_device_attributes - nf_tables device netlink attributes
> *
> * @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
> + * @NFTA_DEVICE_PREFIX: device name prefix, a simple wildcard (NLA_STRING)
> */
> enum nft_devices_attributes {
> NFTA_DEVICE_UNSPEC,
> NFTA_DEVICE_NAME,
> + NFTA_DEVICE_PREFIX,
> __NFTA_DEVICE_MAX
> };
> #define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
> diff --git a/src/mnl.c b/src/mnl.c
> index 43229f2498e55..b532b8ff00c1e 100644
> --- a/src/mnl.c
> +++ b/src/mnl.c
> @@ -795,6 +795,26 @@ static void nft_dev_array_free(const struct nft_dev *dev_array)
> free_const(dev_array);
> }
>
> +static bool is_wildcard_str(const char *str)
> +{
> + size_t len = strlen(str);
> +
> + if (len < 1 || str[len - 1] != '*')
> + return false;
> + if (len < 2 || str[len - 2] != '\\')
> + return true;
> + /* XXX: ignore backslash escaping for now */
Is this comment here still valid?
> + return false;
> +}
> +
> +static void mnl_nft_attr_put_ifname(struct nlmsghdr *nlh, const char *ifname)
> +{
> + uint16_t attr = is_wildcard_str(ifname) ?
> + NFTA_DEVICE_PREFIX : NFTA_DEVICE_NAME;
> +
> + mnl_attr_put_strz(nlh, attr, ifname);
> +}
> +
> static void mnl_nft_chain_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
> {
> const struct expr *dev_expr = cmd->chain->dev_expr;
> @@ -803,14 +823,14 @@ static void mnl_nft_chain_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
> int i, num_devs = 0;
>
> dev_array = nft_dev_array(dev_expr, &num_devs);
> - if (num_devs == 1) {
> + if (num_devs == 1 && !is_wildcard_str(dev_array[0].ifname)) {
> cmd_add_loc(cmd, nlh, dev_array[0].location);
> mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, dev_array[0].ifname);
> } else {
> nest_dev = mnl_attr_nest_start(nlh, NFTA_HOOK_DEVS);
> for (i = 0; i < num_devs; i++) {
> cmd_add_loc(cmd, nlh, dev_array[i].location);
> - mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname);
> + mnl_nft_attr_put_ifname(nlh, dev_array[i].ifname);
> }
> mnl_attr_nest_end(nlh, nest_dev);
> }
> @@ -2091,7 +2111,7 @@ static void mnl_nft_ft_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
> nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS);
> for (i = 0; i < num_devs; i++) {
> cmd_add_loc(cmd, nlh, dev_array[i].location);
> - mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname);
> + mnl_nft_attr_put_ifname(nlh, dev_array[i].ifname);
> }
>
> mnl_attr_nest_end(nlh, nest_dev);
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [nft PATCH v5 2/3] parser_bison: Accept ASTERISK_STRING in flowtable_expr_member
2025-07-31 22:29 ` [nft PATCH v5 2/3] parser_bison: Accept ASTERISK_STRING in flowtable_expr_member Phil Sutter
@ 2025-09-04 15:20 ` Pablo Neira Ayuso
2025-09-04 22:29 ` Phil Sutter
0 siblings, 1 reply; 10+ messages in thread
From: Pablo Neira Ayuso @ 2025-09-04 15:20 UTC (permalink / raw)
To: Phil Sutter; +Cc: netfilter-devel
Hi Phil,
On Fri, Aug 01, 2025 at 12:29:44AM +0200, Phil Sutter wrote:
> All clauses are identical, so instead of adding a third one for
> ASTERISK_STRING, use a single one for 'string' (which combines all three
> variants).
>
> Signed-off-by: Phil Sutter <phil@nwl.cc>
> ---
> Changes since v3:
> - Cover interface wildcards in nft.8
> ---
> doc/nft.txt | 30 ++++++++++++++++++++++++++----
> src/parser_bison.y | 11 +----------
> 2 files changed, 27 insertions(+), 14 deletions(-)
>
> diff --git a/doc/nft.txt b/doc/nft.txt
> index 8712981943d78..42cdd38a27b67 100644
> --- a/doc/nft.txt
> +++ b/doc/nft.txt
> @@ -387,13 +387,19 @@ add table inet mytable
> CHAINS
> ------
> [verse]
> -{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' [*device* 'device'] *priority* 'priority' *;* [*policy* 'policy' *;*] [*comment* 'comment' *;*] *}*]
> +____
> +{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' ['DEVICE'] *priority* 'priority' *;* [*policy* 'policy' *;*] [*comment* 'comment' *;*] *}*]
> {*delete* | *destroy* | *list* | *flush*} *chain* ['family'] 'table' 'chain'
> *list chains* ['family']
> *delete chain* ['family'] 'table' *handle* 'handle'
> *destroy chain* ['family'] 'table' *handle* 'handle'
> *rename chain* ['family'] 'table' 'chain' 'newname'
>
> +'DEVICE' := {*device* 'DEVICE_NAME' | *devices = {* 'DEVICE_LIST' *}*}
> +'DEVICE_LIST' := 'DEVICE_NAME' [*,* 'DEVICE_LIST']
> +'DEVICE_NAME' := 'string' | 'string'***
> +____
> +
> Chains are containers for rules. They exist in two kinds, base chains and
> regular chains. A base chain is an entry point for packets from the networking
> stack, a regular chain may be used as jump target and is used for better rule
> @@ -436,7 +442,7 @@ Apart from the special cases illustrated above (e.g. *nat* type not supporting
>
> * The netdev family supports merely two combinations, namely *filter* type with
> *ingress* hook and *filter* type with *egress* hook. Base chains in this
> - family also require the *device* parameter to be present since they exist per
> + family also require the 'DEVICE' parameter to be present since they exist per
> interface only.
> * The arp family supports only the *input* and *output* hooks, both in chains of type
> *filter*.
> @@ -449,7 +455,13 @@ Apart from the special cases illustrated above (e.g. *nat* type not supporting
> The *device* parameter accepts a network interface name as a string, and is
> required when adding a base chain that filters traffic on the ingress or
> egress hooks. Any ingress or egress chains will only filter traffic from the
> -interface specified in the *device* parameter.
> +interface specified in the *device* parameter. The same base chain may be used
> +for multiple devices by using the *devices* parameter instead.
> +
> +With newer kernels there is also basic support for wildcards in 'DEVICE_NAME'
> +by specifying an asterisk suffix. The chain will apply to all interfaces
> +matching the given prefix. Use the *list hooks* command to see the current
> +status.
Maybe explain here too that newer kernels also allow to pre-register a
match on unexisting devices (specify version), while old kernel fail
with ENOENT?
> The *priority* parameter accepts a signed integer value or a standard priority
> name which specifies the order in which chains with the same *hook* value are
> @@ -763,11 +775,16 @@ per element comment field
> FLOWTABLES
> -----------
> [verse]
> -{*add* | *create*} *flowtable* ['family'] 'table' 'flowtable' *{ hook* 'hook' *priority* 'priority' *; devices = {* 'device'[*,* ...] *} ; }*
> +____
> +{*add* | *create*} *flowtable* ['family'] 'table' 'flowtable' *{ hook* 'hook' *priority* 'priority' *; devices = {* 'DEVICE_LIST' *} ; }*
> *list flowtables* ['family'] ['table']
> {*delete* | *destroy* | *list*} *flowtable* ['family'] 'table' 'flowtable'
> *delete* *flowtable* ['family'] 'table' *handle* 'handle'
>
> +'DEVICE_LIST' := 'DEVICE_NAME' [*,* 'DEVICE_LIST']
> +'DEVICE_NAME' := 'string' | 'string'***
> +____
> +
> Flowtables allow you to accelerate packet forwarding in software. Flowtables
> entries are represented through a tuple that is composed of the input interface,
> source and destination address, source and destination port; and layer 3/4
> @@ -786,6 +803,11 @@ The *priority* can be a signed integer or *filter* which stands for 0. Addition
> and subtraction can be used to set relative priority, e.g. filter + 5 equals to
> 5.
>
> +With newer kernels there is basic support for wildcards in 'DEVICE_LIST' by
> +specifying an asterisk suffix. The flowtable will apply to all interfaces
> +matching the given prefix. Use the *list hooks* command to see the current
> +status.
... to see the
hooks that are that registered per device that match on the wildcard
device.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [nft PATCH v5 1/3] mnl: Support simple wildcards in netdev hooks
2025-09-04 15:16 ` Pablo Neira Ayuso
@ 2025-09-04 22:27 ` Phil Sutter
2025-09-05 11:20 ` Pablo Neira Ayuso
0 siblings, 1 reply; 10+ messages in thread
From: Phil Sutter @ 2025-09-04 22:27 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
On Thu, Sep 04, 2025 at 05:16:19PM +0200, Pablo Neira Ayuso wrote:
> Hi Phil,
>
> NFTA_DEVICE_PREFIX is now available in net.git, let's pick up on this.
>
> On Fri, Aug 01, 2025 at 12:29:43AM +0200, Phil Sutter wrote:
> > When building NFTA_{FLOWTABLE_,}HOOK_DEVS attributes, detect trailing
> > asterisks in interface names and transmit the leading part in a
> > NFTA_DEVICE_PREFIX attribute.
> >
> > Deserialization (i.e., appending asterisk to interface prefixes returned
> > in NFTA_DEVICE_PREFIX atributes happens in libnftnl.
> >
> > Signed-off-by: Phil Sutter <phil@nwl.cc>
> > ---
> > Changes since v4:
> > - Introduce and use NFTA_DEVICE_PREFIX which contains a NUL-terminated
> > string as well but signals the kernel to interpret it as a prefix to
> > match interfaces on.
> > - Do not send wildcards in NFTA_HOOK_DEV: On one hand, the kernel can't
> > detect them anymore since they are NUL-terminated as well. On the
> > other, it would defeat the purpose of having NFTA_DEVICE_PREFIX, which
> > is to not crash old user space.
> >
> > Changes since v3:
> > - Use uint16_t for 'attr' parameter and size_t for 'len' variable
> > - Use mnl_nft_ prefix for the helper function
> >
> > Changes since v2:
> > - Introduce mnl_attr_put_ifname() to perform the conditional
> > mnl_attr_put() parameter adjustment
> > - Sanity-check array index in above function to avoid out-of-bounds
> > access
> > ---
> > include/linux/netfilter/nf_tables.h | 2 ++
> > src/mnl.c | 26 +++++++++++++++++++++++---
> > 2 files changed, 25 insertions(+), 3 deletions(-)
> >
> > diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
> > index f57963e89fd16..b38d4780ae8c8 100644
> > --- a/include/linux/netfilter/nf_tables.h
> > +++ b/include/linux/netfilter/nf_tables.h
> > @@ -1774,10 +1774,12 @@ enum nft_synproxy_attributes {
> > * enum nft_device_attributes - nf_tables device netlink attributes
> > *
> > * @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
> > + * @NFTA_DEVICE_PREFIX: device name prefix, a simple wildcard (NLA_STRING)
> > */
> > enum nft_devices_attributes {
> > NFTA_DEVICE_UNSPEC,
> > NFTA_DEVICE_NAME,
> > + NFTA_DEVICE_PREFIX,
> > __NFTA_DEVICE_MAX
> > };
> > #define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
> > diff --git a/src/mnl.c b/src/mnl.c
> > index 43229f2498e55..b532b8ff00c1e 100644
> > --- a/src/mnl.c
> > +++ b/src/mnl.c
> > @@ -795,6 +795,26 @@ static void nft_dev_array_free(const struct nft_dev *dev_array)
> > free_const(dev_array);
> > }
> >
> > +static bool is_wildcard_str(const char *str)
> > +{
> > + size_t len = strlen(str);
> > +
> > + if (len < 1 || str[len - 1] != '*')
> > + return false;
> > + if (len < 2 || str[len - 2] != '\\')
> > + return true;
> > + /* XXX: ignore backslash escaping for now */
>
> Is this comment here still valid?
Yes, sadly. The above covers for eth* and eth\* but not for eth\\* since
a proper solution didn't quickly come to mind which avoids playing
whack-a-mole. (E.g., does eth\\\\\\* escape the wildcard or not?)
Guess I could just count the number of backslashes immediately preceding
the asterisk and return true if the sum is odd?
Cheers, Phil
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [nft PATCH v5 2/3] parser_bison: Accept ASTERISK_STRING in flowtable_expr_member
2025-09-04 15:20 ` Pablo Neira Ayuso
@ 2025-09-04 22:29 ` Phil Sutter
0 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-09-04 22:29 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
On Thu, Sep 04, 2025 at 05:20:50PM +0200, Pablo Neira Ayuso wrote:
> Hi Phil,
>
> On Fri, Aug 01, 2025 at 12:29:44AM +0200, Phil Sutter wrote:
> > All clauses are identical, so instead of adding a third one for
> > ASTERISK_STRING, use a single one for 'string' (which combines all three
> > variants).
> >
> > Signed-off-by: Phil Sutter <phil@nwl.cc>
> > ---
> > Changes since v3:
> > - Cover interface wildcards in nft.8
> > ---
> > doc/nft.txt | 30 ++++++++++++++++++++++++++----
> > src/parser_bison.y | 11 +----------
> > 2 files changed, 27 insertions(+), 14 deletions(-)
> >
> > diff --git a/doc/nft.txt b/doc/nft.txt
> > index 8712981943d78..42cdd38a27b67 100644
> > --- a/doc/nft.txt
> > +++ b/doc/nft.txt
> > @@ -387,13 +387,19 @@ add table inet mytable
> > CHAINS
> > ------
> > [verse]
> > -{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' [*device* 'device'] *priority* 'priority' *;* [*policy* 'policy' *;*] [*comment* 'comment' *;*] *}*]
> > +____
> > +{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' ['DEVICE'] *priority* 'priority' *;* [*policy* 'policy' *;*] [*comment* 'comment' *;*] *}*]
> > {*delete* | *destroy* | *list* | *flush*} *chain* ['family'] 'table' 'chain'
> > *list chains* ['family']
> > *delete chain* ['family'] 'table' *handle* 'handle'
> > *destroy chain* ['family'] 'table' *handle* 'handle'
> > *rename chain* ['family'] 'table' 'chain' 'newname'
> >
> > +'DEVICE' := {*device* 'DEVICE_NAME' | *devices = {* 'DEVICE_LIST' *}*}
> > +'DEVICE_LIST' := 'DEVICE_NAME' [*,* 'DEVICE_LIST']
> > +'DEVICE_NAME' := 'string' | 'string'***
> > +____
> > +
> > Chains are containers for rules. They exist in two kinds, base chains and
> > regular chains. A base chain is an entry point for packets from the networking
> > stack, a regular chain may be used as jump target and is used for better rule
> > @@ -436,7 +442,7 @@ Apart from the special cases illustrated above (e.g. *nat* type not supporting
> >
> > * The netdev family supports merely two combinations, namely *filter* type with
> > *ingress* hook and *filter* type with *egress* hook. Base chains in this
> > - family also require the *device* parameter to be present since they exist per
> > + family also require the 'DEVICE' parameter to be present since they exist per
> > interface only.
> > * The arp family supports only the *input* and *output* hooks, both in chains of type
> > *filter*.
> > @@ -449,7 +455,13 @@ Apart from the special cases illustrated above (e.g. *nat* type not supporting
> > The *device* parameter accepts a network interface name as a string, and is
> > required when adding a base chain that filters traffic on the ingress or
> > egress hooks. Any ingress or egress chains will only filter traffic from the
> > -interface specified in the *device* parameter.
> > +interface specified in the *device* parameter. The same base chain may be used
> > +for multiple devices by using the *devices* parameter instead.
> > +
> > +With newer kernels there is also basic support for wildcards in 'DEVICE_NAME'
> > +by specifying an asterisk suffix. The chain will apply to all interfaces
> > +matching the given prefix. Use the *list hooks* command to see the current
> > +status.
>
> Maybe explain here too that newer kernels also allow to pre-register a
> match on unexisting devices (specify version), while old kernel fail
> with ENOENT?
ACK, will do!
> > The *priority* parameter accepts a signed integer value or a standard priority
> > name which specifies the order in which chains with the same *hook* value are
> > @@ -763,11 +775,16 @@ per element comment field
> > FLOWTABLES
> > -----------
> > [verse]
> > -{*add* | *create*} *flowtable* ['family'] 'table' 'flowtable' *{ hook* 'hook' *priority* 'priority' *; devices = {* 'device'[*,* ...] *} ; }*
> > +____
> > +{*add* | *create*} *flowtable* ['family'] 'table' 'flowtable' *{ hook* 'hook' *priority* 'priority' *; devices = {* 'DEVICE_LIST' *} ; }*
> > *list flowtables* ['family'] ['table']
> > {*delete* | *destroy* | *list*} *flowtable* ['family'] 'table' 'flowtable'
> > *delete* *flowtable* ['family'] 'table' *handle* 'handle'
> >
> > +'DEVICE_LIST' := 'DEVICE_NAME' [*,* 'DEVICE_LIST']
> > +'DEVICE_NAME' := 'string' | 'string'***
> > +____
> > +
> > Flowtables allow you to accelerate packet forwarding in software. Flowtables
> > entries are represented through a tuple that is composed of the input interface,
> > source and destination address, source and destination port; and layer 3/4
> > @@ -786,6 +803,11 @@ The *priority* can be a signed integer or *filter* which stands for 0. Addition
> > and subtraction can be used to set relative priority, e.g. filter + 5 equals to
> > 5.
> >
> > +With newer kernels there is basic support for wildcards in 'DEVICE_LIST' by
> > +specifying an asterisk suffix. The flowtable will apply to all interfaces
> > +matching the given prefix. Use the *list hooks* command to see the current
> > +status.
>
> ... to see the
> hooks that are that registered per device that match on the wildcard
> device.
LGTM!
Thanks, Phil
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [nft PATCH v5 1/3] mnl: Support simple wildcards in netdev hooks
2025-09-04 22:27 ` Phil Sutter
@ 2025-09-05 11:20 ` Pablo Neira Ayuso
2025-09-30 21:06 ` Phil Sutter
0 siblings, 1 reply; 10+ messages in thread
From: Pablo Neira Ayuso @ 2025-09-05 11:20 UTC (permalink / raw)
To: Phil Sutter, netfilter-devel
On Fri, Sep 05, 2025 at 12:27:28AM +0200, Phil Sutter wrote:
> On Thu, Sep 04, 2025 at 05:16:19PM +0200, Pablo Neira Ayuso wrote:
> > Hi Phil,
> >
> > NFTA_DEVICE_PREFIX is now available in net.git, let's pick up on this.
> >
> > On Fri, Aug 01, 2025 at 12:29:43AM +0200, Phil Sutter wrote:
> > > When building NFTA_{FLOWTABLE_,}HOOK_DEVS attributes, detect trailing
> > > asterisks in interface names and transmit the leading part in a
> > > NFTA_DEVICE_PREFIX attribute.
> > >
> > > Deserialization (i.e., appending asterisk to interface prefixes returned
> > > in NFTA_DEVICE_PREFIX atributes happens in libnftnl.
> > >
> > > Signed-off-by: Phil Sutter <phil@nwl.cc>
> > > ---
> > > Changes since v4:
> > > - Introduce and use NFTA_DEVICE_PREFIX which contains a NUL-terminated
> > > string as well but signals the kernel to interpret it as a prefix to
> > > match interfaces on.
> > > - Do not send wildcards in NFTA_HOOK_DEV: On one hand, the kernel can't
> > > detect them anymore since they are NUL-terminated as well. On the
> > > other, it would defeat the purpose of having NFTA_DEVICE_PREFIX, which
> > > is to not crash old user space.
> > >
> > > Changes since v3:
> > > - Use uint16_t for 'attr' parameter and size_t for 'len' variable
> > > - Use mnl_nft_ prefix for the helper function
> > >
> > > Changes since v2:
> > > - Introduce mnl_attr_put_ifname() to perform the conditional
> > > mnl_attr_put() parameter adjustment
> > > - Sanity-check array index in above function to avoid out-of-bounds
> > > access
> > > ---
> > > include/linux/netfilter/nf_tables.h | 2 ++
> > > src/mnl.c | 26 +++++++++++++++++++++++---
> > > 2 files changed, 25 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
> > > index f57963e89fd16..b38d4780ae8c8 100644
> > > --- a/include/linux/netfilter/nf_tables.h
> > > +++ b/include/linux/netfilter/nf_tables.h
> > > @@ -1774,10 +1774,12 @@ enum nft_synproxy_attributes {
> > > * enum nft_device_attributes - nf_tables device netlink attributes
> > > *
> > > * @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
> > > + * @NFTA_DEVICE_PREFIX: device name prefix, a simple wildcard (NLA_STRING)
> > > */
> > > enum nft_devices_attributes {
> > > NFTA_DEVICE_UNSPEC,
> > > NFTA_DEVICE_NAME,
> > > + NFTA_DEVICE_PREFIX,
> > > __NFTA_DEVICE_MAX
> > > };
> > > #define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
> > > diff --git a/src/mnl.c b/src/mnl.c
> > > index 43229f2498e55..b532b8ff00c1e 100644
> > > --- a/src/mnl.c
> > > +++ b/src/mnl.c
> > > @@ -795,6 +795,26 @@ static void nft_dev_array_free(const struct nft_dev *dev_array)
> > > free_const(dev_array);
> > > }
> > >
> > > +static bool is_wildcard_str(const char *str)
> > > +{
> > > + size_t len = strlen(str);
> > > +
> > > + if (len < 1 || str[len - 1] != '*')
> > > + return false;
> > > + if (len < 2 || str[len - 2] != '\\')
> > > + return true;
> > > + /* XXX: ignore backslash escaping for now */
> >
> > Is this comment here still valid?
>
> Yes, sadly. The above covers for eth* and eth\* but not for eth\\* since
> a proper solution didn't quickly come to mind which avoids playing
> whack-a-mole. (E.g., does eth\\\\\\* escape the wildcard or not?)
>
> Guess I could just count the number of backslashes immediately preceding
> the asterisk and return true if the sum is odd?
Thanks for explaining the comment, this supports eth* and eth\* which
is sufficient at this stage.
For this series:
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [nft PATCH v5 1/3] mnl: Support simple wildcards in netdev hooks
2025-09-05 11:20 ` Pablo Neira Ayuso
@ 2025-09-30 21:06 ` Phil Sutter
0 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-09-30 21:06 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
On Fri, Sep 05, 2025 at 01:20:49PM +0200, Pablo Neira Ayuso wrote:
> On Fri, Sep 05, 2025 at 12:27:28AM +0200, Phil Sutter wrote:
> > On Thu, Sep 04, 2025 at 05:16:19PM +0200, Pablo Neira Ayuso wrote:
> > > Hi Phil,
> > >
> > > NFTA_DEVICE_PREFIX is now available in net.git, let's pick up on this.
> > >
> > > On Fri, Aug 01, 2025 at 12:29:43AM +0200, Phil Sutter wrote:
> > > > When building NFTA_{FLOWTABLE_,}HOOK_DEVS attributes, detect trailing
> > > > asterisks in interface names and transmit the leading part in a
> > > > NFTA_DEVICE_PREFIX attribute.
> > > >
> > > > Deserialization (i.e., appending asterisk to interface prefixes returned
> > > > in NFTA_DEVICE_PREFIX atributes happens in libnftnl.
> > > >
> > > > Signed-off-by: Phil Sutter <phil@nwl.cc>
> > > > ---
> > > > Changes since v4:
> > > > - Introduce and use NFTA_DEVICE_PREFIX which contains a NUL-terminated
> > > > string as well but signals the kernel to interpret it as a prefix to
> > > > match interfaces on.
> > > > - Do not send wildcards in NFTA_HOOK_DEV: On one hand, the kernel can't
> > > > detect them anymore since they are NUL-terminated as well. On the
> > > > other, it would defeat the purpose of having NFTA_DEVICE_PREFIX, which
> > > > is to not crash old user space.
> > > >
> > > > Changes since v3:
> > > > - Use uint16_t for 'attr' parameter and size_t for 'len' variable
> > > > - Use mnl_nft_ prefix for the helper function
> > > >
> > > > Changes since v2:
> > > > - Introduce mnl_attr_put_ifname() to perform the conditional
> > > > mnl_attr_put() parameter adjustment
> > > > - Sanity-check array index in above function to avoid out-of-bounds
> > > > access
> > > > ---
> > > > include/linux/netfilter/nf_tables.h | 2 ++
> > > > src/mnl.c | 26 +++++++++++++++++++++++---
> > > > 2 files changed, 25 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
> > > > index f57963e89fd16..b38d4780ae8c8 100644
> > > > --- a/include/linux/netfilter/nf_tables.h
> > > > +++ b/include/linux/netfilter/nf_tables.h
> > > > @@ -1774,10 +1774,12 @@ enum nft_synproxy_attributes {
> > > > * enum nft_device_attributes - nf_tables device netlink attributes
> > > > *
> > > > * @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
> > > > + * @NFTA_DEVICE_PREFIX: device name prefix, a simple wildcard (NLA_STRING)
> > > > */
> > > > enum nft_devices_attributes {
> > > > NFTA_DEVICE_UNSPEC,
> > > > NFTA_DEVICE_NAME,
> > > > + NFTA_DEVICE_PREFIX,
> > > > __NFTA_DEVICE_MAX
> > > > };
> > > > #define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
> > > > diff --git a/src/mnl.c b/src/mnl.c
> > > > index 43229f2498e55..b532b8ff00c1e 100644
> > > > --- a/src/mnl.c
> > > > +++ b/src/mnl.c
> > > > @@ -795,6 +795,26 @@ static void nft_dev_array_free(const struct nft_dev *dev_array)
> > > > free_const(dev_array);
> > > > }
> > > >
> > > > +static bool is_wildcard_str(const char *str)
> > > > +{
> > > > + size_t len = strlen(str);
> > > > +
> > > > + if (len < 1 || str[len - 1] != '*')
> > > > + return false;
> > > > + if (len < 2 || str[len - 2] != '\\')
> > > > + return true;
> > > > + /* XXX: ignore backslash escaping for now */
> > >
> > > Is this comment here still valid?
> >
> > Yes, sadly. The above covers for eth* and eth\* but not for eth\\* since
> > a proper solution didn't quickly come to mind which avoids playing
> > whack-a-mole. (E.g., does eth\\\\\\* escape the wildcard or not?)
> >
> > Guess I could just count the number of backslashes immediately preceding
> > the asterisk and return true if the sum is odd?
>
> Thanks for explaining the comment, this supports eth* and eth\* which
> is sufficient at this stage.
>
> For this series:
>
> Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
Series applied, thanks!
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-09-30 21:06 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-31 22:29 [nft PATCH v5 0/3] Support wildcard netdev hooks Phil Sutter
2025-07-31 22:29 ` [nft PATCH v5 1/3] mnl: Support simple wildcards in " Phil Sutter
2025-09-04 15:16 ` Pablo Neira Ayuso
2025-09-04 22:27 ` Phil Sutter
2025-09-05 11:20 ` Pablo Neira Ayuso
2025-09-30 21:06 ` Phil Sutter
2025-07-31 22:29 ` [nft PATCH v5 2/3] parser_bison: Accept ASTERISK_STRING in flowtable_expr_member Phil Sutter
2025-09-04 15:20 ` Pablo Neira Ayuso
2025-09-04 22:29 ` Phil Sutter
2025-07-31 22:29 ` [nft PATCH v5 3/3] tests: shell: Test ifname-based hooks Phil Sutter
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).