Skip to content

Commit 43da04a

Browse files
committed
netfilter: nf_tables: atomic dump and reset for stateful objects
This patch adds a new NFT_MSG_GETOBJ_RESET command perform an atomic dump-and-reset of the stateful object. This also comes with add support for atomic dump and reset for counter and quota objects. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent 795595f commit 43da04a

File tree

5 files changed

+85
-23
lines changed

5 files changed

+85
-23
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,8 @@ struct nft_object_type {
997997
struct nft_object *obj);
998998
void (*destroy)(struct nft_object *obj);
999999
int (*dump)(struct sk_buff *skb,
1000-
const struct nft_object *obj);
1000+
struct nft_object *obj,
1001+
bool reset);
10011002
};
10021003

10031004
int nft_register_obj(struct nft_object_type *obj_type);

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ enum nft_verdicts {
8989
* @NFT_MSG_NEWOBJ: create a stateful object (enum nft_obj_attributes)
9090
* @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes)
9191
* @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes)
92+
* @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes)
9293
*/
9394
enum nf_tables_msg_types {
9495
NFT_MSG_NEWTABLE,
@@ -112,6 +113,7 @@ enum nf_tables_msg_types {
112113
NFT_MSG_NEWOBJ,
113114
NFT_MSG_GETOBJ,
114115
NFT_MSG_DELOBJ,
116+
NFT_MSG_GETOBJ_RESET,
115117
NFT_MSG_MAX,
116118
};
117119

net/netfilter/nf_tables_api.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3972,14 +3972,14 @@ static struct nft_object *nft_obj_init(const struct nft_object_type *type,
39723972
}
39733973

39743974
static int nft_object_dump(struct sk_buff *skb, unsigned int attr,
3975-
const struct nft_object *obj)
3975+
struct nft_object *obj, bool reset)
39763976
{
39773977
struct nlattr *nest;
39783978

39793979
nest = nla_nest_start(skb, attr);
39803980
if (!nest)
39813981
goto nla_put_failure;
3982-
if (obj->type->dump(skb, obj) < 0)
3982+
if (obj->type->dump(skb, obj, reset) < 0)
39833983
goto nla_put_failure;
39843984
nla_nest_end(skb, nest);
39853985
return 0;
@@ -4096,7 +4096,7 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
40964096
static int nf_tables_fill_obj_info(struct sk_buff *skb, struct net *net,
40974097
u32 portid, u32 seq, int event, u32 flags,
40984098
int family, const struct nft_table *table,
4099-
const struct nft_object *obj)
4099+
struct nft_object *obj, bool reset)
41004100
{
41014101
struct nfgenmsg *nfmsg;
41024102
struct nlmsghdr *nlh;
@@ -4115,7 +4115,7 @@ static int nf_tables_fill_obj_info(struct sk_buff *skb, struct net *net,
41154115
nla_put_string(skb, NFTA_OBJ_NAME, obj->name) ||
41164116
nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->type->type)) ||
41174117
nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) ||
4118-
nft_object_dump(skb, NFTA_OBJ_DATA, obj))
4118+
nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset))
41194119
goto nla_put_failure;
41204120

41214121
nlmsg_end(skb, nlh);
@@ -4131,10 +4131,14 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
41314131
const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
41324132
const struct nft_af_info *afi;
41334133
const struct nft_table *table;
4134-
const struct nft_object *obj;
41354134
unsigned int idx = 0, s_idx = cb->args[0];
41364135
struct net *net = sock_net(skb->sk);
41374136
int family = nfmsg->nfgen_family;
4137+
struct nft_object *obj;
4138+
bool reset = false;
4139+
4140+
if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET)
4141+
reset = true;
41384142

41394143
rcu_read_lock();
41404144
cb->seq = net->nft.base_seq;
@@ -4156,7 +4160,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
41564160
cb->nlh->nlmsg_seq,
41574161
NFT_MSG_NEWOBJ,
41584162
NLM_F_MULTI | NLM_F_APPEND,
4159-
afi->family, table, obj) < 0)
4163+
afi->family, table, obj, reset) < 0)
41604164
goto done;
41614165

41624166
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
@@ -4183,6 +4187,7 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
41834187
const struct nft_table *table;
41844188
struct nft_object *obj;
41854189
struct sk_buff *skb2;
4190+
bool reset = false;
41864191
u32 objtype;
41874192
int err;
41884193

@@ -4214,9 +4219,12 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
42144219
if (!skb2)
42154220
return -ENOMEM;
42164221

4222+
if (NFNL_MSG_TYPE(nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET)
4223+
reset = true;
4224+
42174225
err = nf_tables_fill_obj_info(skb2, net, NETLINK_CB(skb).portid,
42184226
nlh->nlmsg_seq, NFT_MSG_NEWOBJ, 0,
4219-
family, table, obj);
4227+
family, table, obj, reset);
42204228
if (err < 0)
42214229
goto err;
42224230

@@ -4291,7 +4299,7 @@ static int nf_tables_obj_notify(const struct nft_ctx *ctx,
42914299

42924300
err = nf_tables_fill_obj_info(skb, ctx->net, ctx->portid, ctx->seq,
42934301
event, 0, ctx->afi->family, ctx->table,
4294-
obj);
4302+
obj, false);
42954303
if (err < 0) {
42964304
kfree_skb(skb);
42974305
goto err;
@@ -4482,6 +4490,11 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
44824490
.attr_count = NFTA_OBJ_MAX,
44834491
.policy = nft_obj_policy,
44844492
},
4493+
[NFT_MSG_GETOBJ_RESET] = {
4494+
.call = nf_tables_getobj,
4495+
.attr_count = NFTA_OBJ_MAX,
4496+
.policy = nft_obj_policy,
4497+
},
44854498
};
44864499

44874500
static void nft_chain_commit_update(struct nft_trans *trans)

net/netfilter/nft_counter.c

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ static void nft_counter_obj_destroy(struct nft_object *obj)
100100
nft_counter_do_destroy(priv);
101101
}
102102

103-
static void nft_counter_fetch(const struct nft_counter_percpu __percpu *counter,
103+
static void nft_counter_fetch(struct nft_counter_percpu __percpu *counter,
104104
struct nft_counter *total)
105105
{
106-
const struct nft_counter_percpu *cpu_stats;
106+
struct nft_counter_percpu *cpu_stats;
107107
u64 bytes, packets;
108108
unsigned int seq;
109109
int cpu;
@@ -122,12 +122,52 @@ static void nft_counter_fetch(const struct nft_counter_percpu __percpu *counter,
122122
}
123123
}
124124

125+
static u64 __nft_counter_reset(u64 *counter)
126+
{
127+
u64 ret, old;
128+
129+
do {
130+
old = *counter;
131+
ret = cmpxchg64(counter, old, 0);
132+
} while (ret != old);
133+
134+
return ret;
135+
}
136+
137+
static void nft_counter_reset(struct nft_counter_percpu __percpu *counter,
138+
struct nft_counter *total)
139+
{
140+
struct nft_counter_percpu *cpu_stats;
141+
u64 bytes, packets;
142+
unsigned int seq;
143+
int cpu;
144+
145+
memset(total, 0, sizeof(*total));
146+
for_each_possible_cpu(cpu) {
147+
bytes = packets = 0;
148+
149+
cpu_stats = per_cpu_ptr(counter, cpu);
150+
do {
151+
seq = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
152+
packets += __nft_counter_reset(&cpu_stats->counter.packets);
153+
bytes += __nft_counter_reset(&cpu_stats->counter.bytes);
154+
} while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, seq));
155+
156+
total->packets += packets;
157+
total->bytes += bytes;
158+
}
159+
}
160+
125161
static int nft_counter_do_dump(struct sk_buff *skb,
126-
const struct nft_counter_percpu_priv *priv)
162+
const struct nft_counter_percpu_priv *priv,
163+
bool reset)
127164
{
128165
struct nft_counter total;
129166

130-
nft_counter_fetch(priv->counter, &total);
167+
if (reset)
168+
nft_counter_reset(priv->counter, &total);
169+
else
170+
nft_counter_fetch(priv->counter, &total);
131171

132172
if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes),
133173
NFTA_COUNTER_PAD) ||
@@ -141,11 +181,11 @@ static int nft_counter_do_dump(struct sk_buff *skb,
141181
}
142182

143183
static int nft_counter_obj_dump(struct sk_buff *skb,
144-
const struct nft_object *obj)
184+
struct nft_object *obj, bool reset)
145185
{
146-
const struct nft_counter_percpu_priv *priv = nft_obj_data(obj);
186+
struct nft_counter_percpu_priv *priv = nft_obj_data(obj);
147187

148-
return nft_counter_do_dump(skb, priv);
188+
return nft_counter_do_dump(skb, priv, reset);
149189
}
150190

151191
static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
@@ -178,7 +218,7 @@ static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr)
178218
{
179219
const struct nft_counter_percpu_priv *priv = nft_expr_priv(expr);
180220

181-
return nft_counter_do_dump(skb, priv);
221+
return nft_counter_do_dump(skb, priv, false);
182222
}
183223

184224
static int nft_counter_init(const struct nft_ctx *ctx,

net/netfilter/nft_quota.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,17 @@ static int nft_quota_obj_init(const struct nlattr * const tb[],
8383
return nft_quota_do_init(tb, priv);
8484
}
8585

86-
static int nft_quota_do_dump(struct sk_buff *skb, const struct nft_quota *priv)
86+
static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
87+
bool reset)
8788
{
8889
u32 flags = priv->invert ? NFT_QUOTA_F_INV : 0;
8990
u64 consumed;
9091

91-
consumed = atomic64_read(&priv->consumed);
92+
if (reset)
93+
consumed = atomic64_xchg(&priv->consumed, 0);
94+
else
95+
consumed = atomic64_read(&priv->consumed);
96+
9297
/* Since we inconditionally increment consumed quota for each packet
9398
* that we see, don't go over the quota boundary in what we send to
9499
* userspace.
@@ -108,11 +113,12 @@ static int nft_quota_do_dump(struct sk_buff *skb, const struct nft_quota *priv)
108113
return -1;
109114
}
110115

111-
static int nft_quota_obj_dump(struct sk_buff *skb, const struct nft_object *obj)
116+
static int nft_quota_obj_dump(struct sk_buff *skb, struct nft_object *obj,
117+
bool reset)
112118
{
113119
struct nft_quota *priv = nft_obj_data(obj);
114120

115-
return nft_quota_do_dump(skb, priv);
121+
return nft_quota_do_dump(skb, priv, reset);
116122
}
117123

118124
static struct nft_object_type nft_quota_obj __read_mostly = {
@@ -146,9 +152,9 @@ static int nft_quota_init(const struct nft_ctx *ctx,
146152

147153
static int nft_quota_dump(struct sk_buff *skb, const struct nft_expr *expr)
148154
{
149-
const struct nft_quota *priv = nft_expr_priv(expr);
155+
struct nft_quota *priv = nft_expr_priv(expr);
150156

151-
return nft_quota_do_dump(skb, priv);
157+
return nft_quota_do_dump(skb, priv, false);
152158
}
153159

154160
static struct nft_expr_type nft_quota_type;

0 commit comments

Comments
 (0)