aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-05-30 20:54:47 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-30 20:54:47 -0400
commit90d0e08e574d1aa8553ee6179fcf3bf2b333ca6d (patch)
tree9733281b423aa819f30334fe230ffb1f4644c5d6 /net
parent648d4febcc7cc65f9e242edd26c44f54a8c171e0 (diff)
parentf768e5bdefe1ec9adbf7a116dfb156b73cacb582 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter/IPVS updates for net-next This small patchset contains three accumulated Netfilter/IPVS updates, they are: 1) Refactorize common NAT code by encapsulating it into a helper function, similarly to what we do in other conntrack extensions, from Florian Westphal. 2) A minor format string mismatch fix for IPVS, from Masanari Iida. 3) Add quota support to the netfilter accounting infrastructure, now you can add quotas to accounting objects via the nfnetlink interface and use them from iptables. You can also listen to quota notifications from userspace. This enhancement from Mathieu Poirier. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/iptable_nat.c14
-rw-r--r--net/ipv4/netfilter/nft_chain_nat_ipv4.c12
-rw-r--r--net/ipv6/netfilter/ip6table_nat.c14
-rw-r--r--net/ipv6/netfilter/nft_chain_nat_ipv6.c12
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c2
-rw-r--r--net/netfilter/nf_nat_core.c24
-rw-r--r--net/netfilter/nfnetlink_acct.c85
-rw-r--r--net/netfilter/xt_nfacct.c5
8 files changed, 118 insertions, 50 deletions
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index ee2886126e3d..f1787c04a4dd 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -91,17 +91,9 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops,
91 if (nf_ct_is_untracked(ct)) 91 if (nf_ct_is_untracked(ct))
92 return NF_ACCEPT; 92 return NF_ACCEPT;
93 93
94 nat = nfct_nat(ct); 94 nat = nf_ct_nat_ext_add(ct);
95 if (!nat) { 95 if (nat == NULL)
96 /* NAT module was loaded late. */ 96 return NF_ACCEPT;
97 if (nf_ct_is_confirmed(ct))
98 return NF_ACCEPT;
99 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
100 if (nat == NULL) {
101 pr_debug("failed to add NAT extension\n");
102 return NF_ACCEPT;
103 }
104 }
105 97
106 switch (ctinfo) { 98 switch (ctinfo) {
107 case IP_CT_RELATED: 99 case IP_CT_RELATED:
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
index b5b256d45e67..3964157d826c 100644
--- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c
+++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
@@ -48,15 +48,9 @@ static unsigned int nf_nat_fn(const struct nf_hook_ops *ops,
48 48
49 NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET))); 49 NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
50 50
51 nat = nfct_nat(ct); 51 nat = nf_ct_nat_ext_add(ct);
52 if (nat == NULL) { 52 if (nat == NULL)
53 /* Conntrack module was loaded late, can't add extension. */ 53 return NF_ACCEPT;
54 if (nf_ct_is_confirmed(ct))
55 return NF_ACCEPT;
56 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
57 if (nat == NULL)
58 return NF_ACCEPT;
59 }
60 54
61 switch (ctinfo) { 55 switch (ctinfo) {
62 case IP_CT_RELATED: 56 case IP_CT_RELATED:
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index 84c7f33d0cf8..387d8b8fc18d 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -90,17 +90,9 @@ nf_nat_ipv6_fn(const struct nf_hook_ops *ops,
90 if (nf_ct_is_untracked(ct)) 90 if (nf_ct_is_untracked(ct))
91 return NF_ACCEPT; 91 return NF_ACCEPT;
92 92
93 nat = nfct_nat(ct); 93 nat = nf_ct_nat_ext_add(ct);
94 if (!nat) { 94 if (nat == NULL)
95 /* NAT module was loaded late. */ 95 return NF_ACCEPT;
96 if (nf_ct_is_confirmed(ct))
97 return NF_ACCEPT;
98 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
99 if (nat == NULL) {
100 pr_debug("failed to add NAT extension\n");
101 return NF_ACCEPT;
102 }
103 }
104 96
105 switch (ctinfo) { 97 switch (ctinfo) {
106 case IP_CT_RELATED: 98 case IP_CT_RELATED:
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
index 9c3297a768fd..d189fcb437fe 100644
--- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c
+++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
@@ -47,15 +47,9 @@ static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops,
47 if (ct == NULL || nf_ct_is_untracked(ct)) 47 if (ct == NULL || nf_ct_is_untracked(ct))
48 return NF_ACCEPT; 48 return NF_ACCEPT;
49 49
50 nat = nfct_nat(ct); 50 nat = nf_ct_nat_ext_add(ct);
51 if (nat == NULL) { 51 if (nat == NULL)
52 /* Conntrack module was loaded late, can't add extension. */ 52 return NF_ACCEPT;
53 if (nf_ct_is_confirmed(ct))
54 return NF_ACCEPT;
55 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
56 if (nat == NULL)
57 return NF_ACCEPT;
58 }
59 53
60 switch (ctinfo) { 54 switch (ctinfo) {
61 case IP_CT_RELATED: 55 case IP_CT_RELATED:
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 4f26ee46b51f..d9da8c448c76 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -97,7 +97,7 @@ const char *ip_vs_proto_name(unsigned int proto)
97 return "ICMPv6"; 97 return "ICMPv6";
98#endif 98#endif
99 default: 99 default:
100 sprintf(buf, "IP_%d", proto); 100 sprintf(buf, "IP_%u", proto);
101 return buf; 101 return buf;
102 } 102 }
103} 103}
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 52ca952b802c..09096a670c45 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -358,6 +358,19 @@ out:
358 rcu_read_unlock(); 358 rcu_read_unlock();
359} 359}
360 360
361struct nf_conn_nat *nf_ct_nat_ext_add(struct nf_conn *ct)
362{
363 struct nf_conn_nat *nat = nfct_nat(ct);
364 if (nat)
365 return nat;
366
367 if (!nf_ct_is_confirmed(ct))
368 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
369
370 return nat;
371}
372EXPORT_SYMBOL_GPL(nf_ct_nat_ext_add);
373
361unsigned int 374unsigned int
362nf_nat_setup_info(struct nf_conn *ct, 375nf_nat_setup_info(struct nf_conn *ct,
363 const struct nf_nat_range *range, 376 const struct nf_nat_range *range,
@@ -368,14 +381,9 @@ nf_nat_setup_info(struct nf_conn *ct,
368 struct nf_conn_nat *nat; 381 struct nf_conn_nat *nat;
369 382
370 /* nat helper or nfctnetlink also setup binding */ 383 /* nat helper or nfctnetlink also setup binding */
371 nat = nfct_nat(ct); 384 nat = nf_ct_nat_ext_add(ct);
372 if (!nat) { 385 if (nat == NULL)
373 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); 386 return NF_ACCEPT;
374 if (nat == NULL) {
375 pr_debug("failed to add NAT extension\n");
376 return NF_ACCEPT;
377 }
378 }
379 387
380 NF_CT_ASSERT(maniptype == NF_NAT_MANIP_SRC || 388 NF_CT_ASSERT(maniptype == NF_NAT_MANIP_SRC ||
381 maniptype == NF_NAT_MANIP_DST); 389 maniptype == NF_NAT_MANIP_DST);
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