Commit f111f780ae1abf4cdc464f24293be90c010a04f6
Committed by
Pablo Neira Ayuso
1 parent
1b05756c48
netfilter: nfnetlink_acct: add filter support to nfacct counter list/reset
You can use this to skip accounting objects when listing/resetting via NFNL_MSG_ACCT_GET/NFNL_MSG_ACCT_GET_CTRZERO messages with the NLM_F_DUMP netlink flag. The filtering covers the following cases: 1. No filter specified. In this case, the client will get old behaviour, 2. List/reset counter object only: In this case, you have to use NFACCT_F_QUOTA as mask and value 0. 3. List/reset quota objects only: You have to use NFACCT_F_QUOTA_PKTS as mask and value - the same, for byte based quota mask should be NFACCT_F_QUOTA_BYTES and value - the same. If you want to obtain the object with any quota type (ie. NFACCT_F_QUOTA_PKTS|NFACCT_F_QUOTA_BYTES), you need to perform two dump requests, one to obtain NFACCT_F_QUOTA_PKTS objects and another for NFACCT_F_QUOTA_BYTES. Signed-off-by: Alexey Perevalov <a.perevalov@samsung.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Showing 2 changed files with 62 additions and 0 deletions Side-by-side Diff
include/uapi/linux/netfilter/nfnetlink_acct.h
... | ... | @@ -28,10 +28,18 @@ |
28 | 28 | NFACCT_USE, |
29 | 29 | NFACCT_FLAGS, |
30 | 30 | NFACCT_QUOTA, |
31 | + NFACCT_FILTER, | |
31 | 32 | __NFACCT_MAX |
32 | 33 | }; |
33 | 34 | #define NFACCT_MAX (__NFACCT_MAX - 1) |
34 | 35 | |
36 | +enum nfnl_attr_filter_type { | |
37 | + NFACCT_FILTER_UNSPEC, | |
38 | + NFACCT_FILTER_MASK, | |
39 | + NFACCT_FILTER_VALUE, | |
40 | + __NFACCT_FILTER_MAX | |
41 | +}; | |
42 | +#define NFACCT_FILTER_MAX (__NFACCT_FILTER_MAX - 1) | |
35 | 43 | |
36 | 44 | #endif /* _UAPI_NFNL_ACCT_H_ */ |
net/netfilter/nfnetlink_acct.c
... | ... | @@ -40,6 +40,11 @@ |
40 | 40 | char data[0]; |
41 | 41 | }; |
42 | 42 | |
43 | +struct nfacct_filter { | |
44 | + u32 value; | |
45 | + u32 mask; | |
46 | +}; | |
47 | + | |
43 | 48 | #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES) |
44 | 49 | #define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */ |
45 | 50 | |
... | ... | @@ -181,6 +186,7 @@ |
181 | 186 | nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb) |
182 | 187 | { |
183 | 188 | struct nf_acct *cur, *last; |
189 | + const struct nfacct_filter *filter = cb->data; | |
184 | 190 | |
185 | 191 | if (cb->args[2]) |
186 | 192 | return 0; |
... | ... | @@ -197,6 +203,10 @@ |
197 | 203 | |
198 | 204 | last = NULL; |
199 | 205 | } |
206 | + | |
207 | + if (filter && (cur->flags & filter->mask) != filter->value) | |
208 | + continue; | |
209 | + | |
200 | 210 | if (nfnl_acct_fill_info(skb, NETLINK_CB(cb->skb).portid, |
201 | 211 | cb->nlh->nlmsg_seq, |
202 | 212 | NFNL_MSG_TYPE(cb->nlh->nlmsg_type), |
... | ... | @@ -211,6 +221,38 @@ |
211 | 221 | return skb->len; |
212 | 222 | } |
213 | 223 | |
224 | +static int nfnl_acct_done(struct netlink_callback *cb) | |
225 | +{ | |
226 | + kfree(cb->data); | |
227 | + return 0; | |
228 | +} | |
229 | + | |
230 | +static const struct nla_policy filter_policy[NFACCT_FILTER_MAX + 1] = { | |
231 | + [NFACCT_FILTER_MASK] = { .type = NLA_U32 }, | |
232 | + [NFACCT_FILTER_VALUE] = { .type = NLA_U32 }, | |
233 | +}; | |
234 | + | |
235 | +static struct nfacct_filter * | |
236 | +nfacct_filter_alloc(const struct nlattr * const attr) | |
237 | +{ | |
238 | + struct nfacct_filter *filter; | |
239 | + struct nlattr *tb[NFACCT_FILTER_MAX + 1]; | |
240 | + int err; | |
241 | + | |
242 | + err = nla_parse_nested(tb, NFACCT_FILTER_MAX, attr, filter_policy); | |
243 | + if (err < 0) | |
244 | + return ERR_PTR(err); | |
245 | + | |
246 | + filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL); | |
247 | + if (!filter) | |
248 | + return ERR_PTR(-ENOMEM); | |
249 | + | |
250 | + filter->mask = ntohl(nla_get_be32(tb[NFACCT_FILTER_MASK])); | |
251 | + filter->value = ntohl(nla_get_be32(tb[NFACCT_FILTER_VALUE])); | |
252 | + | |
253 | + return filter; | |
254 | +} | |
255 | + | |
214 | 256 | static int |
215 | 257 | nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb, |
216 | 258 | const struct nlmsghdr *nlh, const struct nlattr * const tb[]) |
217 | 259 | |
... | ... | @@ -222,7 +264,18 @@ |
222 | 264 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
223 | 265 | struct netlink_dump_control c = { |
224 | 266 | .dump = nfnl_acct_dump, |
267 | + .done = nfnl_acct_done, | |
225 | 268 | }; |
269 | + | |
270 | + if (tb[NFACCT_FILTER]) { | |
271 | + struct nfacct_filter *filter; | |
272 | + | |
273 | + filter = nfacct_filter_alloc(tb[NFACCT_FILTER]); | |
274 | + if (IS_ERR(filter)) | |
275 | + return PTR_ERR(filter); | |
276 | + | |
277 | + c.data = filter; | |
278 | + } | |
226 | 279 | return netlink_dump_start(nfnl, skb, nlh, &c); |
227 | 280 | } |
228 | 281 | |
... | ... | @@ -314,6 +367,7 @@ |
314 | 367 | [NFACCT_PKTS] = { .type = NLA_U64 }, |
315 | 368 | [NFACCT_FLAGS] = { .type = NLA_U32 }, |
316 | 369 | [NFACCT_QUOTA] = { .type = NLA_U64 }, |
370 | + [NFACCT_FILTER] = {.type = NLA_NESTED }, | |
317 | 371 | }; |
318 | 372 | |
319 | 373 | static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = { |