netfilter: meta: add PRANDOM support
Subsystems (3)
Florian Westphal
maintainerPATCH 1/1 netfilter: meta: add PRANDOM support
Can be used to randomly match a packet, e.g. for statistical traffic sampling.
See commit 3ad0040573b0c00f8848
("bpf: split state from prandom_u32() and consolidate {c, e}BPF prngs") for more info why this doesn't use prandom_u32 directly.
Unlike bpf nft_meta can be built as a module, so add an EXPORT_SYMBOL for prandom_seed_full_state too.
--- include/uapi/linux/netfilter/nf_tables.h | 2 ++ lib/random32.c | 1 + net/netfilter/nft_meta.c | 15 +++++++++++++++ 3 files changed, 18 insertions(+)
include/uapi/linux/netfilter/nf_tables.h +2 -0
@@ -681,6 +681,7 @@ enum nft_exthdr_attributes {* @NFT_META_IIFGROUP: packet input interface group * @NFT_META_OIFGROUP: packet output interface group * @NFT_META_CGROUP: socket control group (skb->sk->sk_classid) +* @NFT_META_PRANDOM: a 32bit pseudo-random number */ enum nft_meta_keys {NFT_META_LEN ,
@@ -707,6 +708,7 @@ enum nft_meta_keys {NFT_META_IIFGROUP ,NFT_META_OIFGROUP ,NFT_META_CGROUP , + NFT_META_PRANDOM, };/**
lib/random32.c +1 -0
@@ -255,6 +255,7 @@ void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)prandom_warmup (state); } } +EXPORT_SYMBOL (prandom_seed_full_state);/* * Generate better values after random number generator
net/netfilter/nft_meta.c +15 -0
@@ -28,6 +28,8 @@#include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */ +static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state); +void nft_meta_get_eval (const struct nft_expr *expr,struct nft_regs *regs,const struct nft_pktinfo *pkt)
@@ -181,6 +183,11 @@ void nft_meta_get_eval(const struct nft_expr *expr, *dest =sock_cgroup_classid (&sk->sk_cgrp_data);break ;#endif +case NFT_META_PRANDOM : { +struct rnd_state *state =this_cpu_ptr (&nft_prandom_state); + *dest =prandom_u32_state (state); +break ; + }default :WARN_ON (1 ); goto err;
@@ -241,6 +248,7 @@ int nft_meta_get_init(const struct nft_ctx *ctx, {struct nft_meta *priv =nft_expr_priv (expr);unsigned int len; +static bool prand_inited__read_mostly ; priv->key =ntohl (nla_get_be32 (tb[NFTA_META_KEY ]));switch (priv->key) {
@@ -277,6 +285,13 @@ int nft_meta_get_init(const struct nft_ctx *ctx,case NFT_META_OIFNAME : len =IFNAMSIZ ;break ; +case NFT_META_PRANDOM : +if (!prand_inited) { +prandom_seed_full_state (&nft_prandom_state); + prand_inited = true; + } + len =sizeof (u32); +break ;default :return -EOPNOTSUPP ; }
Signature · 1 line
2.4.10
Hi Florian,
Quoted 12 lines · Florian Westphal
Can be used to randomly match a packet, e.g. for statistical traffic sampling.
See commit
3ad0040573b0c00f8848
("bpf: split state fromprandom_u32()and consolidate {c, e}BPF prngs") for more info why this doesn't useprandom_u32directly.Unlike bpf
nft_metacan be built as a module, so add anEXPORT_SYMBOLforprandom_seed_full_statetoo.Cc Daniel Borkmann <[email protected]>Signed-off-by Florian Westphal <[email protected]>
[...]
Quoted 9 lines
net/netfilter/nft_meta.c +1
-0@@ -241,6 +248,7 @@ int nft_meta_get_init(const struct nft_ctx *ctx, {struct nft_meta *priv =nft_expr_priv (expr);unsigned int len; +static bool prand_inited__read_mostly ; priv->key =ntohl (nla_get_be32 (tb[NFTA_META_KEY ]));switch (priv->key) {
net/netfilter/nft_meta.c int nft_meta_get_init(const struct nft_ctx *ctx, · line 292
Quoted 8 lines
net/netfilter/nft_meta.c +5
-0@@ -277,6 +285,13 @@ int nft_meta_get_init(const struct nft_ctx *ctx,case NFT_META_OIFNAME : len =IFNAMSIZ ;break ; +case NFT_META_PRANDOM : +if (!prand_inited) { +prandom_seed_full_state (&nft_prandom_state); + prand_inited = true; + }
Should this be: prandom_init_once() ?
net/netfilter/nft_meta.c int nft_meta_get_init(const struct nft_ctx *ctx, · line 297
Quoted 6 lines
net/netfilter/nft_meta.c +2
-0+ len =sizeof (u32); +break ;default :return -EOPNOTSUPP ; }
Thanks,
Daniel
Florian Westphal
maintainerQuoted 7 lines · Daniel Borkmann
net/netfilter/nft_meta.c int nft_meta_get_init(const struct nft_ctx *ctx, · line 292
Quoted 5 lines
net/netfilter/nft_meta.c +5
-0+case NFT_META_PRANDOM : +if (!prand_inited) { +prandom_seed_full_state (&nft_prandom_state); + prand_inited = true; + }Should this be:
prandom_init_once()?
Thought about that but this is slowpath so I considered the use of static key magic a bit overkill....
I don't mind, if you think prandom_init_once is prefereable I'll respin.
Let me know, thanks!
Quoted 9 lines · Florian Westphal
Quoted 7 lines · Daniel Borkmann
net/netfilter/nft_meta.c int nft_meta_get_init(const struct nft_ctx *ctx, · line 292
Quoted 5 lines
net/netfilter/nft_meta.c +5
-0+case NFT_META_PRANDOM : +if (!prand_inited) { +prandom_seed_full_state (&nft_prandom_state); + prand_inited = true; + }Should this be:
prandom_init_once()?
Quoted 4 lines
Thought about that but this is slowpath so I considered the use of static key magic a bit overkill....
I don't mind, if you think
prandom_init_onceis prefereable I'll respin.
You'd have the benefit that the prng init would be race free. nft_meta_get_init() could be called in parallel from multiple CPUs, right?
Quoted 1 line
Let me know, thanks!
Florian Westphal
maintainerQuoted 10 lines · Daniel Borkmann
Quoted 9 lines · Florian Westphal
Quoted 7 lines · Daniel Borkmann
net/netfilter/nft_meta.c int nft_meta_get_init(const struct nft_ctx *ctx, · line 292
Quoted 5 lines
net/netfilter/nft_meta.c +5
-0+case NFT_META_PRANDOM : +if (!prand_inited) { +prandom_seed_full_state (&nft_prandom_state); + prand_inited = true; + }Should this be:
prandom_init_once()?
Quoted 7 lines
Quoted 4 lines
Thought about that but this is slowpath so I considered the use of static key magic a bit overkill....
I don't mind, if you think
prandom_init_onceis prefereable I'll respin.You'd have the benefit that the prng init would be race free.
nft_meta_get_init()could be called in parallel from multiple CPUs, right?
We're serialized by nftables' nfnetlink mutex.
I guess I'll just send a V2 and use prandom_init_once after all.
Thanks!