* [nf-next PATCH 1/3] netfilter: nf_tables: commit_notify: Support varying groups
2025-06-12 13:34 [nf-next PATCH 0/3] netfilter: nf_tables: Report found devices when creating a netdev hook Phil Sutter
@ 2025-06-12 13:34 ` Phil Sutter
2025-06-12 13:34 ` [nf-next PATCH 2/3] netfilter: nf_tables: Support enqueueing device notifications Phil Sutter
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Phil Sutter @ 2025-06-12 13:34 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Expect users to enqueue notifications for various groups. The first
message for a new group will flush the existing batch and start a new
one.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
net/netfilter/nf_tables_api.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 24c71ecb2179..da12a5424e6d 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1193,13 +1193,16 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
struct nftnl_skb_parms {
bool report;
+ unsigned int group;
};
#define NFT_CB(skb) (*(struct nftnl_skb_parms*)&((skb)->cb))
-static void nft_notify_enqueue(struct sk_buff *skb, bool report,
+static void nft_notify_enqueue(struct sk_buff *skb,
+ bool report, unsigned int group,
struct list_head *notify_list)
{
NFT_CB(skb).report = report;
+ NFT_CB(skb).group = group;
list_add_tail(&skb->list, notify_list);
}
@@ -1229,7 +1232,8 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
}
nft_net = nft_pernet(ctx->net);
- nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+ nft_notify_enqueue(skb, ctx->report, NFNLGRP_NFTABLES,
+ &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -2100,7 +2104,8 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event,
}
nft_net = nft_pernet(ctx->net);
- nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+ nft_notify_enqueue(skb, ctx->report, NFNLGRP_NFTABLES,
+ &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -3714,7 +3719,8 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
goto err;
}
- nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+ nft_notify_enqueue(skb, ctx->report, NFNLGRP_NFTABLES,
+ &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -4971,7 +4977,8 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx,
goto err;
}
- nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+ nft_notify_enqueue(skb, ctx->report, NFNLGRP_NFTABLES,
+ &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -6630,7 +6637,8 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
}
nft_net = nft_pernet(net);
- nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+ nft_notify_enqueue(skb, ctx->report, NFNLGRP_NFTABLES,
+ &nft_net->notify_list);
return;
err:
nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -8702,7 +8710,8 @@ __nft_obj_notify(struct net *net, const struct nft_table *table,
goto err;
}
- nft_notify_enqueue(skb, report, &nft_net->notify_list);
+ nft_notify_enqueue(skb, report, NFNLGRP_NFTABLES,
+ &nft_net->notify_list);
return;
err:
nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -9614,7 +9623,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
goto err;
}
- nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+ nft_notify_enqueue(skb, ctx->report, NFNLGRP_NFTABLES,
+ &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -10750,20 +10760,22 @@ static void nft_commit_notify(struct net *net, u32 portid)
continue;
}
len -= skb->len;
- if (len > 0 && NFT_CB(skb).report == NFT_CB(batch_skb).report) {
+ if (len > 0 &&
+ NFT_CB(skb).report == NFT_CB(batch_skb).report &&
+ NFT_CB(skb).group == NFT_CB(batch_skb).group) {
data = skb_put(batch_skb, skb->len);
memcpy(data, skb->data, skb->len);
list_del(&skb->list);
kfree_skb(skb);
continue;
}
- nfnetlink_send(batch_skb, net, portid, NFNLGRP_NFTABLES,
+ nfnetlink_send(batch_skb, net, portid, NFT_CB(batch_skb).group,
NFT_CB(batch_skb).report, GFP_KERNEL);
goto new_batch;
}
if (batch_skb) {
- nfnetlink_send(batch_skb, net, portid, NFNLGRP_NFTABLES,
+ nfnetlink_send(batch_skb, net, portid, NFT_CB(batch_skb).group,
NFT_CB(batch_skb).report, GFP_KERNEL);
}
--
2.49.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [nf-next PATCH 2/3] netfilter: nf_tables: Support enqueueing device notifications
2025-06-12 13:34 [nf-next PATCH 0/3] netfilter: nf_tables: Report found devices when creating a netdev hook Phil Sutter
2025-06-12 13:34 ` [nf-next PATCH 1/3] netfilter: nf_tables: commit_notify: Support varying groups Phil Sutter
@ 2025-06-12 13:34 ` Phil Sutter
2025-06-12 13:34 ` [nf-next PATCH 3/3] netfilter: nf_tables: Extend chain/flowtable notifications Phil Sutter
2025-07-04 8:00 ` [nf-next PATCH 0/3] netfilter: nf_tables: Report found devices when creating a netdev hook Pablo Neira Ayuso
3 siblings, 0 replies; 6+ messages in thread
From: Phil Sutter @ 2025-06-12 13:34 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
This will be used for generating notifications during commit in a
follow-up patch. No functional change intended.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
include/net/netfilter/nf_tables.h | 3 ++-
net/netfilter/nf_tables_api.c | 26 ++++++++++++++++++--------
net/netfilter/nft_chain_filter.c | 2 +-
3 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index e4d8e451e935..9bff7fadcf33 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1145,7 +1145,8 @@ void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
struct nft_hook;
void nf_tables_chain_device_notify(const struct nft_chain *chain,
const struct nft_hook *hook,
- const struct net_device *dev, int event);
+ const struct net_device *dev, int event,
+ bool report, struct list_head *notify_list);
enum nft_chain_types {
NFT_CHAIN_T_DEFAULT = 0,
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index da12a5424e6d..635332bad1b1 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -9699,7 +9699,8 @@ EXPORT_SYMBOL_GPL(nft_hook_find_ops_rcu);
static void
nf_tables_device_notify(const struct nft_table *table, int attr,
const char *name, const struct nft_hook *hook,
- const struct net_device *dev, int event)
+ const struct net_device *dev, int event,
+ bool report, struct list_head *notify_list)
{
struct net *net = dev_net(dev);
struct nlmsghdr *nlh;
@@ -9727,8 +9728,12 @@ nf_tables_device_notify(const struct nft_table *table, int attr,
goto err;
nlmsg_end(skb, nlh);
- nfnetlink_send(skb, net, 0, NFNLGRP_NFT_DEV,
- nlmsg_report(nlh), GFP_KERNEL);
+
+ if (notify_list)
+ nft_notify_enqueue(skb, report, NFNLGRP_NFT_DEV, notify_list);
+ else
+ nfnetlink_send(skb, net, 0, NFNLGRP_NFT_DEV,
+ report, GFP_KERNEL);
return;
err:
if (skb)
@@ -9739,19 +9744,23 @@ nf_tables_device_notify(const struct nft_table *table, int attr,
void
nf_tables_chain_device_notify(const struct nft_chain *chain,
const struct nft_hook *hook,
- const struct net_device *dev, int event)
+ const struct net_device *dev, int event,
+ bool report, struct list_head *notify_list)
{
nf_tables_device_notify(chain->table, NFTA_DEVICE_CHAIN,
- chain->name, hook, dev, event);
+ chain->name, hook, dev, event,
+ report, notify_list);
}
static void
nf_tables_flowtable_device_notify(const struct nft_flowtable *ft,
const struct nft_hook *hook,
- const struct net_device *dev, int event)
+ const struct net_device *dev, int event,
+ bool report, struct list_head *notify_list)
{
nf_tables_device_notify(ft->table, NFTA_DEVICE_FLOWTABLE,
- ft->name, hook, dev, event);
+ ft->name, hook, dev, event,
+ report, notify_list);
}
static int nft_flowtable_event(unsigned long event, struct net_device *dev,
@@ -9801,7 +9810,8 @@ static int nft_flowtable_event(unsigned long event, struct net_device *dev,
list_add_tail_rcu(&ops->list, &hook->ops_list);
break;
}
- nf_tables_flowtable_device_notify(flowtable, hook, dev, event);
+ nf_tables_flowtable_device_notify(flowtable, hook, dev, event,
+ false, NULL);
break;
}
return 0;
diff --git a/net/netfilter/nft_chain_filter.c b/net/netfilter/nft_chain_filter.c
index 846d48ba8965..17845cf24038 100644
--- a/net/netfilter/nft_chain_filter.c
+++ b/net/netfilter/nft_chain_filter.c
@@ -364,7 +364,7 @@ static int nft_netdev_event(unsigned long event, struct net_device *dev,
break;
}
nf_tables_chain_device_notify(&basechain->chain,
- hook, dev, event);
+ hook, dev, event, false, NULL);
break;
}
return 0;
--
2.49.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [nf-next PATCH 3/3] netfilter: nf_tables: Extend chain/flowtable notifications
2025-06-12 13:34 [nf-next PATCH 0/3] netfilter: nf_tables: Report found devices when creating a netdev hook Phil Sutter
2025-06-12 13:34 ` [nf-next PATCH 1/3] netfilter: nf_tables: commit_notify: Support varying groups Phil Sutter
2025-06-12 13:34 ` [nf-next PATCH 2/3] netfilter: nf_tables: Support enqueueing device notifications Phil Sutter
@ 2025-06-12 13:34 ` Phil Sutter
2025-07-04 8:00 ` [nf-next PATCH 0/3] netfilter: nf_tables: Report found devices when creating a netdev hook Pablo Neira Ayuso
3 siblings, 0 replies; 6+ messages in thread
From: Phil Sutter @ 2025-06-12 13:34 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
When creating a flowtable (or netdev-family chain), matching interfaces
are searched for given hook specs. Send newdev notifications for those.
Same with deldev notifications when deleting a flowtable or chain.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
net/netfilter/nf_tables_api.c | 100 ++++++++++++++++++++++++++++++++++
1 file changed, 100 insertions(+)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 635332bad1b1..8952b50b0224 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -9752,6 +9752,48 @@ nf_tables_chain_device_notify(const struct nft_chain *chain,
report, notify_list);
}
+static void
+nf_tables_chain_devices_notify(struct nft_ctx *ctx, int event,
+ const struct list_head *hook_list)
+{
+ struct nftables_pernet *nft_net = nft_pernet(ctx->net);
+ const struct nft_base_chain *basechain;
+ struct nf_hook_ops *ops;
+ struct nft_hook *hook;
+ int nd_event;
+
+ if (!ctx->report &&
+ !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFT_DEV))
+ return;
+
+ if (!nft_is_base_chain(ctx->chain))
+ return;
+
+ basechain = nft_base_chain(ctx->chain);
+
+ if (!nft_base_chain_netdev(ctx->chain->table->family,
+ basechain->ops.hooknum))
+ return;
+
+ if (!hook_list)
+ hook_list = &basechain->hook_list;
+
+ if (event == NFT_MSG_NEWCHAIN)
+ nd_event = NETDEV_REGISTER;
+ else
+ nd_event = NETDEV_UNREGISTER;
+
+ list_for_each_entry_rcu(hook, hook_list, list,
+ lockdep_commit_lock_is_held(ctx->net)) {
+ list_for_each_entry(ops, &hook->ops_list, list) {
+ nf_tables_chain_device_notify(ctx->chain, hook,
+ ops->dev, nd_event,
+ ctx->report,
+ &nft_net->notify_list);
+ }
+ }
+}
+
static void
nf_tables_flowtable_device_notify(const struct nft_flowtable *ft,
const struct nft_hook *hook,
@@ -9763,6 +9805,40 @@ nf_tables_flowtable_device_notify(const struct nft_flowtable *ft,
report, notify_list);
}
+static void
+nft_flowtable_devices_notify(struct nft_ctx *ctx,
+ struct nft_flowtable *flowtable,
+ struct list_head *hook_list,
+ int event)
+{
+ struct nftables_pernet *nft_net = nft_pernet(ctx->net);
+ struct nf_hook_ops *ops;
+ struct nft_hook *hook;
+ int nd_event;
+
+ if (!ctx->report &&
+ !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFT_DEV))
+ return;
+
+ if (!hook_list)
+ hook_list = &flowtable->hook_list;
+
+ if (event == NFT_MSG_NEWFLOWTABLE)
+ nd_event = NETDEV_REGISTER;
+ else
+ nd_event = NETDEV_UNREGISTER;
+
+ list_for_each_entry_rcu(hook, hook_list, list,
+ lockdep_commit_lock_is_held(ctx->net)) {
+ list_for_each_entry(ops, &hook->ops_list, list) {
+ nf_tables_flowtable_device_notify(flowtable, hook,
+ ops->dev, nd_event,
+ ctx->report,
+ &nft_net->notify_list);
+ }
+ }
+}
+
static int nft_flowtable_event(unsigned long event, struct net_device *dev,
struct nft_flowtable *flowtable, bool changename)
{
@@ -11033,6 +11109,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_chain_commit_update(nft_trans_container_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN,
&nft_trans_chain_hooks(trans));
+ nf_tables_chain_devices_notify(&ctx, NFT_MSG_NEWCHAIN,
+ &nft_trans_chain_hooks(trans));
list_splice(&nft_trans_chain_hooks(trans),
&nft_trans_basechain(trans)->hook_list);
/* trans destroyed after rcu grace period */
@@ -11040,12 +11118,16 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_chain_commit_drop_policy(nft_trans_container_chain(trans));
nft_clear(net, nft_trans_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL);
+ nf_tables_chain_devices_notify(&ctx, NFT_MSG_NEWCHAIN,
+ NULL);
nft_trans_destroy(trans);
}
break;
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
if (nft_trans_chain_update(trans)) {
+ nf_tables_chain_devices_notify(&ctx, NFT_MSG_DELCHAIN,
+ &nft_trans_chain_hooks(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN,
&nft_trans_chain_hooks(trans));
if (!(table->flags & NFT_TABLE_F_DORMANT)) {
@@ -11055,6 +11137,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
}
} else {
nft_chain_del(nft_trans_chain(trans));
+ nf_tables_chain_devices_notify(&ctx, NFT_MSG_DELCHAIN,
+ NULL);
nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN,
NULL);
nf_tables_unregister_hook(ctx.net, ctx.table,
@@ -11163,6 +11247,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_trans_flowtable(trans),
&nft_trans_flowtable_hooks(trans),
NFT_MSG_NEWFLOWTABLE);
+ nft_flowtable_devices_notify(&ctx,
+ nft_trans_flowtable(trans),
+ &nft_trans_flowtable_hooks(trans),
+ NFT_MSG_NEWFLOWTABLE);
list_splice(&nft_trans_flowtable_hooks(trans),
&nft_trans_flowtable(trans)->hook_list);
} else {
@@ -11171,12 +11259,20 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_trans_flowtable(trans),
NULL,
NFT_MSG_NEWFLOWTABLE);
+ nft_flowtable_devices_notify(&ctx,
+ nft_trans_flowtable(trans),
+ NULL,
+ NFT_MSG_NEWFLOWTABLE);
}
nft_trans_destroy(trans);
break;
case NFT_MSG_DELFLOWTABLE:
case NFT_MSG_DESTROYFLOWTABLE:
if (nft_trans_flowtable_update(trans)) {
+ nft_flowtable_devices_notify(&ctx,
+ nft_trans_flowtable(trans),
+ &nft_trans_flowtable_hooks(trans),
+ trans->msg_type);
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
&nft_trans_flowtable_hooks(trans),
@@ -11186,6 +11282,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
&nft_trans_flowtable_hooks(trans));
} else {
list_del_rcu(&nft_trans_flowtable(trans)->list);
+ nft_flowtable_devices_notify(&ctx,
+ nft_trans_flowtable(trans),
+ NULL,
+ trans->msg_type);
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
NULL,
--
2.49.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [nf-next PATCH 0/3] netfilter: nf_tables: Report found devices when creating a netdev hook
2025-06-12 13:34 [nf-next PATCH 0/3] netfilter: nf_tables: Report found devices when creating a netdev hook Phil Sutter
` (2 preceding siblings ...)
2025-06-12 13:34 ` [nf-next PATCH 3/3] netfilter: nf_tables: Extend chain/flowtable notifications Phil Sutter
@ 2025-07-04 8:00 ` Pablo Neira Ayuso
2025-07-04 13:18 ` Phil Sutter
3 siblings, 1 reply; 6+ messages in thread
From: Pablo Neira Ayuso @ 2025-07-04 8:00 UTC (permalink / raw)
To: Phil Sutter; +Cc: netfilter-devel
On Thu, Jun 12, 2025 at 03:34:13PM +0200, Phil Sutter wrote:
> Previously, NEWDEV/DELDEV notifications were emitted for new/renamed
> devices added to a chain or flowtable only. For user space to fully
> comprehend which interfaces a hook binds to, these notifications have to
> be sent for matching devices at hook creation time, too.
>
> This series extends the notify list to support messages for varying
> groups so it may be reused by the NFNLGRP_NFT_DEV messages (patch 1),
> adjusts the device_notify routines to support enqueueing the message
> instead of sending it right away (patch 2) and finally adds extra notify
> calls to nf_tables_commit() (patch 3).
Fine with these series, I am preparing a nf-next pull request, I plan
to include them.
As this goes ahead in providing NEWDEV/DELDEV events for ruleset
updates, I think GETDEV is needed to complete things.
Regarding userspace, I think there only one item remaining to be
discussed, which is how to expose device notifications.
I would suggest to add a separated:
monitor devices
Thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [nf-next PATCH 0/3] netfilter: nf_tables: Report found devices when creating a netdev hook
2025-07-04 8:00 ` [nf-next PATCH 0/3] netfilter: nf_tables: Report found devices when creating a netdev hook Pablo Neira Ayuso
@ 2025-07-04 13:18 ` Phil Sutter
0 siblings, 0 replies; 6+ messages in thread
From: Phil Sutter @ 2025-07-04 13:18 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
On Fri, Jul 04, 2025 at 10:00:41AM +0200, Pablo Neira Ayuso wrote:
> On Thu, Jun 12, 2025 at 03:34:13PM +0200, Phil Sutter wrote:
> > Previously, NEWDEV/DELDEV notifications were emitted for new/renamed
> > devices added to a chain or flowtable only. For user space to fully
> > comprehend which interfaces a hook binds to, these notifications have to
> > be sent for matching devices at hook creation time, too.
> >
> > This series extends the notify list to support messages for varying
> > groups so it may be reused by the NFNLGRP_NFT_DEV messages (patch 1),
> > adjusts the device_notify routines to support enqueueing the message
> > instead of sending it right away (patch 2) and finally adds extra notify
> > calls to nf_tables_commit() (patch 3).
>
> Fine with these series, I am preparing a nf-next pull request, I plan
> to include them.
>
> As this goes ahead in providing NEWDEV/DELDEV events for ruleset
> updates, I think GETDEV is needed to complete things.
>
> Regarding userspace, I think there only one item remaining to be
> discussed, which is how to expose device notifications.
>
> I would suggest to add a separated:
>
> monitor devices
My local tree has "monitor hooks", but it's a trivial change and
"devices" is probably a more intuitive name for something that enables
NEWDEV/DELDEV messages. :)
Thanks, Phil
^ permalink raw reply [flat|nested] 6+ messages in thread