Skip to content

Commit 624d7a8

Browse files
author
Paolo Abeni
committed
Merge tag 'nf-next-25-01-11' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next
Pablo Neira Ayuso says: ==================== Netfilter/IPVS updates for net-next The following patchset contains a small batch of Netfilter/IPVS updates for net-next: 1) Remove unused genmask parameter in nf_tables_addchain() 2) Speed up reads from /proc/net/ip_vs_conn, from Florian Westphal. 3) Skip empty buckets in hashlimit to avoid atomic operations that results in false positive reports by syzbot with lockdep enabled, patch from Eric Dumazet. 4) Add conntrack event timestamps available via ctnetlink, from Florian Westphal. netfilter pull request 25-01-11 * tag 'nf-next-25-01-11' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next: netfilter: conntrack: add conntrack event timestamp netfilter: xt_hashlimit: htable_selective_cleanup() optimization ipvs: speed up reads from ip_vs_conn proc file netfilter: nf_tables: remove the genmask parameter ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents a8d0066 + 601731f commit 624d7a8

File tree

7 files changed

+97
-27
lines changed

7 files changed

+97
-27
lines changed

include/net/netfilter/nf_conntrack_ecache.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/netfilter/nf_conntrack_common.h>
1313
#include <linux/netfilter/nf_conntrack_tuple_common.h>
1414
#include <net/netfilter/nf_conntrack_extend.h>
15+
#include <asm/local64.h>
1516

1617
enum nf_ct_ecache_state {
1718
NFCT_ECACHE_DESTROY_FAIL, /* tried but failed to send destroy event */
@@ -20,6 +21,9 @@ enum nf_ct_ecache_state {
2021

2122
struct nf_conntrack_ecache {
2223
unsigned long cache; /* bitops want long */
24+
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
25+
local64_t timestamp; /* event timestamp, in nanoseconds */
26+
#endif
2327
u16 ctmask; /* bitmask of ct events to be delivered */
2428
u16 expmask; /* bitmask of expect events to be delivered */
2529
u32 missed; /* missed events */
@@ -108,6 +112,14 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
108112
if (e == NULL)
109113
return;
110114

115+
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
116+
/* renew only if this is the first cached event, so that the
117+
* timestamp reflects the first, not the last, generated event.
118+
*/
119+
if (local64_read(&e->timestamp) && READ_ONCE(e->cache) == 0)
120+
local64_set(&e->timestamp, ktime_get_real_ns());
121+
#endif
122+
111123
set_bit(event, &e->cache);
112124
#endif
113125
}

include/uapi/linux/netfilter/nfnetlink_conntrack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ enum ctattr_type {
5757
CTA_SYNPROXY,
5858
CTA_FILTER,
5959
CTA_STATUS_MASK,
60+
CTA_TIMESTAMP_EVENT,
6061
__CTA_MAX
6162
};
6263
#define CTA_MAX (__CTA_MAX - 1)

net/netfilter/ipvs/ip_vs_conn.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,28 +1046,35 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,
10461046
#ifdef CONFIG_PROC_FS
10471047
struct ip_vs_iter_state {
10481048
struct seq_net_private p;
1049-
struct hlist_head *l;
1049+
unsigned int bucket;
1050+
unsigned int skip_elems;
10501051
};
10511052

1052-
static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos)
1053+
static void *ip_vs_conn_array(struct ip_vs_iter_state *iter)
10531054
{
10541055
int idx;
10551056
struct ip_vs_conn *cp;
1056-
struct ip_vs_iter_state *iter = seq->private;
10571057

1058-
for (idx = 0; idx < ip_vs_conn_tab_size; idx++) {
1058+
for (idx = iter->bucket; idx < ip_vs_conn_tab_size; idx++) {
1059+
unsigned int skip = 0;
1060+
10591061
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
10601062
/* __ip_vs_conn_get() is not needed by
10611063
* ip_vs_conn_seq_show and ip_vs_conn_sync_seq_show
10621064
*/
1063-
if (pos-- == 0) {
1064-
iter->l = &ip_vs_conn_tab[idx];
1065+
if (skip >= iter->skip_elems) {
1066+
iter->bucket = idx;
10651067
return cp;
10661068
}
1069+
1070+
++skip;
10671071
}
1072+
1073+
iter->skip_elems = 0;
10681074
cond_resched_rcu();
10691075
}
10701076

1077+
iter->bucket = idx;
10711078
return NULL;
10721079
}
10731080

@@ -1076,38 +1083,37 @@ static void *ip_vs_conn_seq_start(struct seq_file *seq, loff_t *pos)
10761083
{
10771084
struct ip_vs_iter_state *iter = seq->private;
10781085

1079-
iter->l = NULL;
10801086
rcu_read_lock();
1081-
return *pos ? ip_vs_conn_array(seq, *pos - 1) :SEQ_START_TOKEN;
1087+
if (*pos == 0) {
1088+
iter->skip_elems = 0;
1089+
iter->bucket = 0;
1090+
return SEQ_START_TOKEN;
1091+
}
1092+
1093+
return ip_vs_conn_array(iter);
10821094
}
10831095

10841096
static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos)
10851097
{
10861098
struct ip_vs_conn *cp = v;
10871099
struct ip_vs_iter_state *iter = seq->private;
10881100
struct hlist_node *e;
1089-
struct hlist_head *l = iter->l;
1090-
int idx;
10911101

10921102
++*pos;
10931103
if (v == SEQ_START_TOKEN)
1094-
return ip_vs_conn_array(seq, 0);
1104+
return ip_vs_conn_array(iter);
10951105

10961106
/* more on same hash chain? */
10971107
e = rcu_dereference(hlist_next_rcu(&cp->c_list));
1098-
if (e)
1108+
if (e) {
1109+
iter->skip_elems++;
10991110
return hlist_entry(e, struct ip_vs_conn, c_list);
1100-
1101-
idx = l - ip_vs_conn_tab;
1102-
while (++idx < ip_vs_conn_tab_size) {
1103-
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
1104-
iter->l = &ip_vs_conn_tab[idx];
1105-
return cp;
1106-
}
1107-
cond_resched_rcu();
11081111
}
1109-
iter->l = NULL;
1110-
return NULL;
1112+
1113+
iter->skip_elems = 0;
1114+
iter->bucket++;
1115+
1116+
return ip_vs_conn_array(iter);
11111117
}
11121118

11131119
static void ip_vs_conn_seq_stop(struct seq_file *seq, void *v)

net/netfilter/nf_conntrack_ecache.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,14 @@ static int __nf_conntrack_eventmask_report(struct nf_conntrack_ecache *e,
162162
return ret;
163163
}
164164

165+
static void nf_ct_ecache_tstamp_refresh(struct nf_conntrack_ecache *e)
166+
{
167+
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
168+
if (local64_read(&e->timestamp))
169+
local64_set(&e->timestamp, ktime_get_real_ns());
170+
#endif
171+
}
172+
165173
int nf_conntrack_eventmask_report(unsigned int events, struct nf_conn *ct,
166174
u32 portid, int report)
167175
{
@@ -186,6 +194,8 @@ int nf_conntrack_eventmask_report(unsigned int events, struct nf_conn *ct,
186194
/* This is a resent of a destroy event? If so, skip missed */
187195
missed = e->portid ? 0 : e->missed;
188196

197+
nf_ct_ecache_tstamp_refresh(e);
198+
189199
ret = __nf_conntrack_eventmask_report(e, events, missed, &item);
190200
if (unlikely(ret < 0 && (events & (1 << IPCT_DESTROY)))) {
191201
/* This is a destroy event that has been triggered by a process,
@@ -297,6 +307,18 @@ void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state)
297307
}
298308
}
299309

310+
static void nf_ct_ecache_tstamp_new(const struct nf_conn *ct, struct nf_conntrack_ecache *e)
311+
{
312+
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
313+
u64 ts = 0;
314+
315+
if (nf_ct_ext_exist(ct, NF_CT_EXT_TSTAMP))
316+
ts = ktime_get_real_ns();
317+
318+
local64_set(&e->timestamp, ts);
319+
#endif
320+
}
321+
300322
bool nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp)
301323
{
302324
struct net *net = nf_ct_net(ct);
@@ -326,6 +348,7 @@ bool nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp
326348

327349
e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
328350
if (e) {
351+
nf_ct_ecache_tstamp_new(ct, e);
329352
e->ctmask = ctmask;
330353
e->expmask = expmask;
331354
}

net/netfilter/nf_conntrack_netlink.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,23 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
383383
#endif
384384

385385
#ifdef CONFIG_NF_CONNTRACK_EVENTS
386+
static int
387+
ctnetlink_dump_event_timestamp(struct sk_buff *skb, const struct nf_conn *ct)
388+
{
389+
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
390+
const struct nf_conntrack_ecache *e = nf_ct_ecache_find(ct);
391+
392+
if (e) {
393+
u64 ts = local64_read(&e->timestamp);
394+
395+
if (ts)
396+
return nla_put_be64(skb, CTA_TIMESTAMP_EVENT,
397+
cpu_to_be64(ts), CTA_TIMESTAMP_PAD);
398+
}
399+
#endif
400+
return 0;
401+
}
402+
386403
static inline int ctnetlink_label_size(const struct nf_conn *ct)
387404
{
388405
struct nf_conn_labels *labels = nf_ct_labels_find(ct);
@@ -717,6 +734,9 @@ static size_t ctnetlink_nlmsg_size(const struct nf_conn *ct)
717734
#endif
718735
+ ctnetlink_proto_size(ct)
719736
+ ctnetlink_label_size(ct)
737+
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
738+
+ nla_total_size(sizeof(u64)) /* CTA_TIMESTAMP_EVENT */
739+
#endif
720740
;
721741
}
722742

@@ -838,6 +858,10 @@ ctnetlink_conntrack_event(unsigned int events, const struct nf_ct_event *item)
838858
if (ctnetlink_dump_mark(skb, ct, events & (1 << IPCT_MARK)))
839859
goto nla_put_failure;
840860
#endif
861+
862+
if (ctnetlink_dump_event_timestamp(skb, ct))
863+
goto nla_put_failure;
864+
841865
nlmsg_end(skb, nlh);
842866
err = nfnetlink_send(skb, net, item->portid, group, item->report,
843867
GFP_ATOMIC);
@@ -1557,6 +1581,7 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
15571581
.len = NF_CT_LABELS_MAX_SIZE },
15581582
[CTA_FILTER] = { .type = NLA_NESTED },
15591583
[CTA_STATUS_MASK] = { .type = NLA_U32 },
1584+
[CTA_TIMESTAMP_EVENT] = { .type = NLA_REJECT },
15601585
};
15611586

15621587
static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data)

net/netfilter/nf_tables_api.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,9 +2598,8 @@ int nft_chain_add(struct nft_table *table, struct nft_chain *chain)
25982598

25992599
static u64 chain_id;
26002600

2601-
static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
2602-
u8 policy, u32 flags,
2603-
struct netlink_ext_ack *extack)
2601+
static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 policy,
2602+
u32 flags, struct netlink_ext_ack *extack)
26042603
{
26052604
const struct nlattr * const *nla = ctx->nla;
26062605
struct nft_table *table = ctx->table;
@@ -3038,7 +3037,7 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
30383037
extack);
30393038
}
30403039

3041-
return nf_tables_addchain(&ctx, family, genmask, policy, flags, extack);
3040+
return nf_tables_addchain(&ctx, family, policy, flags, extack);
30423041
}
30433042

30443043
static int nft_delchain_hook(struct nft_ctx *ctx,

net/netfilter/xt_hashlimit.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,11 +363,15 @@ static void htable_selective_cleanup(struct xt_hashlimit_htable *ht, bool select
363363
unsigned int i;
364364

365365
for (i = 0; i < ht->cfg.size; i++) {
366+
struct hlist_head *head = &ht->hash[i];
366367
struct dsthash_ent *dh;
367368
struct hlist_node *n;
368369

370+
if (hlist_empty(head))
371+
continue;
372+
369373
spin_lock_bh(&ht->lock);
370-
hlist_for_each_entry_safe(dh, n, &ht->hash[i], node) {
374+
hlist_for_each_entry_safe(dh, n, head, node) {
371375
if (time_after_eq(jiffies, dh->expires) || select_all)
372376
dsthash_free(ht, dh);
373377
}

0 commit comments

Comments
 (0)