Commit f111f780ae1abf4cdc464f24293be90c010a04f6

Authored by Alexey Perevalov
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] = {