aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Poirier <mathieu.poirier@linaro.org>2014-04-20 20:57:36 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2014-04-29 12:25:14 -0400
commit683399eddb9fff742b1a14c5a5d03e12bfc0afff (patch)
treee810034ef24dd4f9a57cd9c3137563050bfa7015
parent1404c3ab9810ab155db5e5368af69d4b20ea5aab (diff)
netfilter: nfnetlink_acct: Adding quota support to accounting framework
nfacct objects already support accounting at the byte and packet level. As such it is a natural extension to add the possiblity to define a ceiling limit for both metrics. All the support for quotas itself is added to nfnetlink acctounting framework to stay coherent with current accounting object management. Quota limit checks are implemented in xt_nfacct filter where statistic collection is already done. Pablo Neira Ayuso has also contributed to this feature. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/linux/netfilter/nfnetlink_acct.h8
-rw-r--r--include/uapi/linux/netfilter/nfnetlink.h2
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_acct.h9
-rw-r--r--net/netfilter/nfnetlink_acct.c85
-rw-r--r--net/netfilter/xt_nfacct.c5
5 files changed, 107 insertions, 2 deletions
diff --git a/include/linux/netfilter/nfnetlink_acct.h b/include/linux/netfilter/nfnetlink_acct.h
index b2e85e59f760..6ec975748742 100644
--- a/include/linux/netfilter/nfnetlink_acct.h
+++ b/include/linux/netfilter/nfnetlink_acct.h
@@ -3,11 +3,17 @@
3 3
4#include <uapi/linux/netfilter/nfnetlink_acct.h> 4#include <uapi/linux/netfilter/nfnetlink_acct.h>
5 5
6enum {
7 NFACCT_NO_QUOTA = -1,
8 NFACCT_UNDERQUOTA,
9 NFACCT_OVERQUOTA,
10};
6 11
7struct nf_acct; 12struct nf_acct;
8 13
9struct nf_acct *nfnl_acct_find_get(const char *filter_name); 14struct nf_acct *nfnl_acct_find_get(const char *filter_name);
10void nfnl_acct_put(struct nf_acct *acct); 15void nfnl_acct_put(struct nf_acct *acct);
11void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct); 16void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct);
12 17extern int nfnl_acct_overquota(const struct sk_buff *skb,
18 struct nf_acct *nfacct);
13#endif /* _NFNL_ACCT_H */ 19#endif /* _NFNL_ACCT_H */
diff --git a/include/uapi/linux/netfilter/nfnetlink.h b/include/uapi/linux/netfilter/nfnetlink.h
index 596ddd45253c..354a7e5e50f2 100644
--- a/include/uapi/linux/netfilter/nfnetlink.h
+++ b/include/uapi/linux/netfilter/nfnetlink.h
@@ -20,6 +20,8 @@ enum nfnetlink_groups {
20#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY 20#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
21 NFNLGRP_NFTABLES, 21 NFNLGRP_NFTABLES,
22#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES 22#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES
23 NFNLGRP_ACCT_QUOTA,
24#define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA
23 __NFNLGRP_MAX, 25 __NFNLGRP_MAX,
24}; 26};
25#define NFNLGRP_MAX (__NFNLGRP_MAX - 1) 27#define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
diff --git a/include/uapi/linux/netfilter/nfnetlink_acct.h b/include/uapi/linux/netfilter/nfnetlink_acct.h
index c7b6269e760b..51404ec19022 100644
--- a/include/uapi/linux/netfilter/nfnetlink_acct.h
+++ b/include/uapi/linux/netfilter/nfnetlink_acct.h
@@ -10,15 +10,24 @@ enum nfnl_acct_msg_types {
10 NFNL_MSG_ACCT_GET, 10 NFNL_MSG_ACCT_GET,
11 NFNL_MSG_ACCT_GET_CTRZERO, 11 NFNL_MSG_ACCT_GET_CTRZERO,
12 NFNL_MSG_ACCT_DEL, 12 NFNL_MSG_ACCT_DEL,
13 NFNL_MSG_ACCT_OVERQUOTA,
13 NFNL_MSG_ACCT_MAX 14 NFNL_MSG_ACCT_MAX
14}; 15};
15 16
17enum nfnl_acct_flags {
18 NFACCT_F_QUOTA_PKTS = (1 << 0),
19 NFACCT_F_QUOTA_BYTES = (1 << 1),
20 NFACCT_F_OVERQUOTA = (1 << 2), /* can't be set from userspace */
21};
22
16enum nfnl_acct_type { 23enum nfnl_acct_type {
17 NFACCT_UNSPEC, 24 NFACCT_UNSPEC,
18 NFACCT_NAME, 25 NFACCT_NAME,
19 NFACCT_PKTS, 26 NFACCT_PKTS,
20 NFACCT_BYTES, 27 NFACCT_BYTES,
21 NFACCT_USE, 28 NFACCT_USE,
29 NFACCT_FLAGS,
30 NFACCT_QUOTA,
22 __NFACCT_MAX 31 __NFACCT_MAX
23}; 32};
24#define NFACCT_MAX (__NFACCT_MAX - 1) 33#define NFACCT_MAX (__NFACCT_MAX - 1)
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
index c7b6d466a662..70e86bbb3637 100644
--- a/net/netfilter/nfnetlink_acct.c
+++ b/net/netfilter/nfnetlink_acct.c
@@ -32,18 +32,24 @@ static LIST_HEAD(nfnl_acct_list);
32struct nf_acct { 32struct nf_acct {
33 atomic64_t pkts; 33 atomic64_t pkts;
34 atomic64_t bytes; 34 atomic64_t bytes;
35 unsigned long flags;
35 struct list_head head; 36 struct list_head head;
36 atomic_t refcnt; 37 atomic_t refcnt;
37 char name[NFACCT_NAME_MAX]; 38 char name[NFACCT_NAME_MAX];
38 struct rcu_head rcu_head; 39 struct rcu_head rcu_head;
40 char data[0];
39}; 41};
40 42
43#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
44
41static int 45static int
42nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, 46nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
43 const struct nlmsghdr *nlh, const struct nlattr * const tb[]) 47 const struct nlmsghdr *nlh, const struct nlattr * const tb[])
44{ 48{
45 struct nf_acct *nfacct, *matching = NULL; 49 struct nf_acct *nfacct, *matching = NULL;
46 char *acct_name; 50 char *acct_name;
51 unsigned int size = 0;
52 u32 flags = 0;
47 53
48 if (!tb[NFACCT_NAME]) 54 if (!tb[NFACCT_NAME])
49 return -EINVAL; 55 return -EINVAL;
@@ -68,15 +74,39 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
68 /* reset counters if you request a replacement. */ 74 /* reset counters if you request a replacement. */
69 atomic64_set(&matching->pkts, 0); 75 atomic64_set(&matching->pkts, 0);
70 atomic64_set(&matching->bytes, 0); 76 atomic64_set(&matching->bytes, 0);
77 smp_mb__before_clear_bit();
78 /* reset overquota flag if quota is enabled. */
79 if ((matching->flags & NFACCT_F_QUOTA))
80 clear_bit(NFACCT_F_OVERQUOTA, &matching->flags);
71 return 0; 81 return 0;
72 } 82 }
73 return -EBUSY; 83 return -EBUSY;
74 } 84 }
75 85
76 nfacct = kzalloc(sizeof(struct nf_acct), GFP_KERNEL); 86 nfacct = kzalloc(sizeof(struct nf_acct), GFP_KERNEL);
87 if (tb[NFACCT_FLAGS]) {
88 flags = ntohl(nla_get_be32(tb[NFACCT_FLAGS]));
89 if (flags & ~NFACCT_F_QUOTA)
90 return -EOPNOTSUPP;
91 if ((flags & NFACCT_F_QUOTA) == NFACCT_F_QUOTA)
92 return -EINVAL;
93 if (flags & NFACCT_F_OVERQUOTA)
94 return -EINVAL;
95
96 size += sizeof(u64);
97 }
98
99 nfacct = kzalloc(sizeof(struct nf_acct) + size, GFP_KERNEL);
77 if (nfacct == NULL) 100 if (nfacct == NULL)
78 return -ENOMEM; 101 return -ENOMEM;
79 102
103 if (flags & NFACCT_F_QUOTA) {
104 u64 *quota = (u64 *)nfacct->data;
105
106 *quota = be64_to_cpu(nla_get_be64(tb[NFACCT_QUOTA]));
107 nfacct->flags = flags;
108 }
109
80 strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX); 110 strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX);
81 111
82 if (tb[NFACCT_BYTES]) { 112 if (tb[NFACCT_BYTES]) {
@@ -117,6 +147,9 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
117 if (type == NFNL_MSG_ACCT_GET_CTRZERO) { 147 if (type == NFNL_MSG_ACCT_GET_CTRZERO) {
118 pkts = atomic64_xchg(&acct->pkts, 0); 148 pkts = atomic64_xchg(&acct->pkts, 0);
119 bytes = atomic64_xchg(&acct->bytes, 0); 149 bytes = atomic64_xchg(&acct->bytes, 0);
150 smp_mb__before_clear_bit();
151 if (acct->flags & NFACCT_F_QUOTA)
152 clear_bit(NFACCT_F_OVERQUOTA, &acct->flags);
120 } else { 153 } else {
121 pkts = atomic64_read(&acct->pkts); 154 pkts = atomic64_read(&acct->pkts);
122 bytes = atomic64_read(&acct->bytes); 155 bytes = atomic64_read(&acct->bytes);
@@ -125,7 +158,13 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
125 nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes)) || 158 nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes)) ||
126 nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt)))) 159 nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt))))
127 goto nla_put_failure; 160 goto nla_put_failure;
161 if (acct->flags & NFACCT_F_QUOTA) {
162 u64 *quota = (u64 *)acct->data;
128 163
164 if (nla_put_be32(skb, NFACCT_FLAGS, htonl(acct->flags)) ||
165 nla_put_be64(skb, NFACCT_QUOTA, cpu_to_be64(*quota)))
166 goto nla_put_failure;
167 }
129 nlmsg_end(skb, nlh); 168 nlmsg_end(skb, nlh);
130 return skb->len; 169 return skb->len;
131 170
@@ -270,6 +309,8 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
270 [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 }, 309 [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 },
271 [NFACCT_BYTES] = { .type = NLA_U64 }, 310 [NFACCT_BYTES] = { .type = NLA_U64 },
272 [NFACCT_PKTS] = { .type = NLA_U64 }, 311 [NFACCT_PKTS] = { .type = NLA_U64 },
312 [NFACCT_FLAGS] = { .type = NLA_U32 },
313 [NFACCT_QUOTA] = { .type = NLA_U64 },
273}; 314};
274 315
275static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = { 316static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
@@ -336,6 +377,50 @@ void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct)
336} 377}
337EXPORT_SYMBOL_GPL(nfnl_acct_update); 378EXPORT_SYMBOL_GPL(nfnl_acct_update);
338 379
380static void nfnl_overquota_report(struct nf_acct *nfacct)
381{
382 int ret;
383 struct sk_buff *skb;
384
385 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
386 if (skb == NULL)
387 return;
388
389 ret = nfnl_acct_fill_info(skb, 0, 0, NFNL_MSG_ACCT_OVERQUOTA, 0,
390 nfacct);
391 if (ret <= 0) {
392 kfree_skb(skb);
393 return;
394 }
395 netlink_broadcast(init_net.nfnl, skb, 0, NFNLGRP_ACCT_QUOTA,
396 GFP_ATOMIC);
397}
398
399int nfnl_acct_overquota(const struct sk_buff *skb, struct nf_acct *nfacct)
400{
401 u64 now;
402 u64 *quota;
403 int ret = NFACCT_UNDERQUOTA;
404
405 /* no place here if we don't have a quota */
406 if (!(nfacct->flags & NFACCT_F_QUOTA))
407 return NFACCT_NO_QUOTA;
408
409 quota = (u64 *)nfacct->data;
410 now = (nfacct->flags & NFACCT_F_QUOTA_PKTS) ?
411 atomic64_read(&nfacct->pkts) : atomic64_read(&nfacct->bytes);
412
413 ret = now > *quota;
414
415 if (now >= *quota &&
416 !test_and_set_bit(NFACCT_F_OVERQUOTA, &nfacct->flags)) {
417 nfnl_overquota_report(nfacct);
418 }
419
420 return ret;
421}
422EXPORT_SYMBOL_GPL(nfnl_acct_overquota);
423
339static int __init nfnl_acct_init(void) 424static int __init nfnl_acct_init(void)
340{ 425{
341 int ret; 426 int ret;
diff --git a/net/netfilter/xt_nfacct.c b/net/netfilter/xt_nfacct.c
index b3be0ef21f19..8c646ed9c921 100644
--- a/net/netfilter/xt_nfacct.c
+++ b/net/netfilter/xt_nfacct.c
@@ -21,11 +21,14 @@ MODULE_ALIAS("ip6t_nfacct");
21 21
22static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par) 22static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par)
23{ 23{
24 int overquota;
24 const struct xt_nfacct_match_info *info = par->targinfo; 25 const struct xt_nfacct_match_info *info = par->targinfo;
25 26
26 nfnl_acct_update(skb, info->nfacct); 27 nfnl_acct_update(skb, info->nfacct);
27 28
28 return true; 29 overquota = nfnl_acct_overquota(skb, info->nfacct);
30
31 return overquota == NFACCT_UNDERQUOTA ? false : true;
29} 32}
30 33
31static int 34static int