From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: davem@davemloft.net, netdev@vger.kernel.org, kuba@kernel.org,
pabeni@redhat.com, edumazet@google.com, fw@strlen.de
Subject: [PATCH net-next 16/16] netfilter: nf_tables: set element timeout update support
Date: Fri, 6 Sep 2024 01:29:20 +0200 [thread overview]
Message-ID: <20240905232920.5481-17-pablo@netfilter.org> (raw)
In-Reply-To: <20240905232920.5481-1-pablo@netfilter.org>
Store new timeout and expiration in transaction object, use them to
update elements from .commit path. Otherwise, discard update if .abort
path is exercised.
Use update_flags in the transaction to note whether the timeout,
expiration, or both need to be updated.
Annotate access to timeout extension now that it can be updated while
lockless read access is possible.
Reject timeout updates on elements with no timeout extension.
Element transaction remains in the 96 bytes kmalloc slab on x86_64 after
this update.
This patch requires ("netfilter: nf_tables: use timestamp to check for
set element timeout") to make sure an element does not expire while
transaction is ongoing.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_tables.h | 16 ++++++++++-
net/netfilter/nf_tables_api.c | 47 ++++++++++++++++++++++++++++---
net/netfilter/nft_dynset.c | 2 +-
3 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 7511918dce6f..49708e7e1339 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -833,7 +833,7 @@ static inline bool __nft_set_elem_expired(const struct nft_set_ext *ext,
u64 tstamp)
{
if (!nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) ||
- nft_set_ext_timeout(ext)->timeout == 0)
+ READ_ONCE(nft_set_ext_timeout(ext)->timeout) == 0)
return false;
return time_after_eq64(tstamp, READ_ONCE(nft_set_ext_timeout(ext)->expiration));
@@ -1749,10 +1749,18 @@ struct nft_trans_table {
#define nft_trans_table_update(trans) \
nft_trans_container_table(trans)->update
+enum nft_trans_elem_flags {
+ NFT_TRANS_UPD_TIMEOUT = (1 << 0),
+ NFT_TRANS_UPD_EXPIRATION = (1 << 1),
+};
+
struct nft_trans_elem {
struct nft_trans nft_trans;
struct nft_set *set;
struct nft_elem_priv *elem_priv;
+ u64 timeout;
+ u64 expiration;
+ u8 update_flags;
bool bound;
};
@@ -1762,6 +1770,12 @@ struct nft_trans_elem {
nft_trans_container_elem(trans)->set
#define nft_trans_elem_priv(trans) \
nft_trans_container_elem(trans)->elem_priv
+#define nft_trans_elem_update_flags(trans) \
+ nft_trans_container_elem(trans)->update_flags
+#define nft_trans_elem_timeout(trans) \
+ nft_trans_container_elem(trans)->timeout
+#define nft_trans_elem_expiration(trans) \
+ nft_trans_container_elem(trans)->expiration
#define nft_trans_elem_set_bound(trans) \
nft_trans_container_elem(trans)->bound
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index ed85b10edb32..57259b5f3ef5 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -5815,7 +5815,7 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
goto nla_put_failure;
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) {
- u64 timeout = nft_set_ext_timeout(ext)->timeout;
+ u64 timeout = READ_ONCE(nft_set_ext_timeout(ext)->timeout);
u64 set_timeout = READ_ONCE(set->timeout);
__be64 msecs = 0;
@@ -6852,6 +6852,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
struct nft_data_desc desc;
enum nft_registers dreg;
struct nft_trans *trans;
+ u8 update_flags;
u64 expiration;
u64 timeout;
int err, i;
@@ -7163,8 +7164,30 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF) &&
*nft_set_ext_obj(ext) != *nft_set_ext_obj(ext2)))
goto err_element_clash;
- else if (!(nlmsg_flags & NLM_F_EXCL))
+ else if (!(nlmsg_flags & NLM_F_EXCL)) {
err = 0;
+ if (nft_set_ext_exists(ext2, NFT_SET_EXT_TIMEOUT)) {
+ update_flags = 0;
+ if (timeout != nft_set_ext_timeout(ext2)->timeout) {
+ nft_trans_elem_timeout(trans) = timeout;
+ if (expiration == 0)
+ expiration = timeout;
+
+ update_flags |= NFT_TRANS_UPD_TIMEOUT;
+ }
+ if (expiration) {
+ nft_trans_elem_expiration(trans) = expiration;
+ update_flags |= NFT_TRANS_UPD_EXPIRATION;
+ }
+
+ if (update_flags) {
+ nft_trans_elem_priv(trans) = elem_priv;
+ nft_trans_elem_update_flags(trans) = update_flags;
+ nft_trans_commit_list_add_tail(ctx->net, trans);
+ goto err_elem_free;
+ }
+ }
+ }
} else if (err == -ENOTEMPTY) {
/* ENOTEMPTY reports overlapping between this element
* and an existing one.
@@ -10489,7 +10512,22 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_NEWSETELEM:
te = nft_trans_container_elem(trans);
- nft_setelem_activate(net, te->set, te->elem_priv);
+ if (te->update_flags) {
+ const struct nft_set_ext *ext =
+ nft_set_elem_ext(te->set, te->elem_priv);
+
+ if (te->update_flags & NFT_TRANS_UPD_TIMEOUT) {
+ WRITE_ONCE(nft_set_ext_timeout(ext)->timeout,
+ te->timeout);
+ }
+ if (te->update_flags & NFT_TRANS_UPD_EXPIRATION) {
+ WRITE_ONCE(nft_set_ext_timeout(ext)->expiration,
+ get_jiffies_64() + te->expiration);
+ }
+ } else {
+ nft_setelem_activate(net, te->set, te->elem_priv);
+ }
+
nf_tables_setelem_notify(&ctx, te->set,
te->elem_priv,
NFT_MSG_NEWSETELEM);
@@ -10789,7 +10827,8 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWSETELEM:
- if (nft_trans_elem_set_bound(trans)) {
+ if (nft_trans_elem_update_flags(trans) ||
+ nft_trans_elem_set_bound(trans)) {
nft_trans_destroy(trans);
break;
}
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index 6a10305de24b..88922e0e8e83 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -95,7 +95,7 @@ void nft_dynset_eval(const struct nft_expr *expr,
expr, regs, &ext)) {
if (priv->op == NFT_DYNSET_OP_UPDATE &&
nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
- nft_set_ext_timeout(ext)->timeout != 0) {
+ READ_ONCE(nft_set_ext_timeout(ext)->timeout) != 0) {
timeout = priv->timeout ? : READ_ONCE(set->timeout);
WRITE_ONCE(nft_set_ext_timeout(ext)->expiration, get_jiffies_64() + timeout);
}
--
2.30.2
prev parent reply other threads:[~2024-09-05 23:29 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-05 23:29 [PATCH net-next 00/16] Netfilter updates for net-next Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 01/16] netfilter: ctnetlink: support CTA_FILTER for flush Pablo Neira Ayuso
2024-09-07 2:10 ` patchwork-bot+netdevbpf
2024-09-05 23:29 ` [PATCH net-next 02/16] netfilter: nft_counter: Use u64_stats_t for statistic Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 03/16] netfilter: Use kmemdup_array instead of kmemdup for multiple allocation Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 04/16] netfilter: conntrack: Convert to use ERR_CAST() Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 05/16] netfilter: nf_tables: drop unused 3rd argument from validate callback ops Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 06/16] netfilter: nf_tables: Correct spelling in nf_tables.h Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 07/16] netfilter: nf_tables: Add missing Kernel doc Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 08/16] netfilter: nf_tables: elements with timeout below CONFIG_HZ never expire Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 09/16] netfilter: nf_tables: reject element expiration with no timeout Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 10/16] netfilter: nf_tables: reject expiration higher than timeout Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 11/16] netfilter: nf_tables: remove annotation to access set timeout while holding lock Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 12/16] netfilter: nft_dynset: annotate data-races around set timeout Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 13/16] netfilter: nf_tables: annotate data-races around element expiration Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 14/16] netfilter: nf_tables: consolidate timeout extension for elements Pablo Neira Ayuso
2024-09-05 23:29 ` [PATCH net-next 15/16] netfilter: nf_tables: zero timeout means element never times out Pablo Neira Ayuso
2024-09-05 23:29 ` Pablo Neira Ayuso [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240905232920.5481-17-pablo@netfilter.org \
--to=pablo@netfilter.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.