History

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. ====================

David S. Miller committed 12 years ago

Commit 90d0e082 parents 648d4fe f768e5b12 files · +138 −51Browse files

Unified · Split

12 files
  1. include/linux/netfilter/nfnetlink_acct.h +7 −1
  2. include/net/netfilter/nf_nat.h +2 −0
  3. include/uapi/linux/netfilter/nfnetlink.h +2 −0
  4. include/uapi/linux/netfilter/nfnetlink_acct.h +9 −0
  5. net/ipv4/netfilter/iptable_nat.c +3 −11
  6. net/ipv4/netfilter/nft_chain_nat_ipv4.c +3 −9
  7. net/ipv6/netfilter/ip6table_nat.c +3 −11
  8. net/ipv6/netfilter/nft_chain_nat_ipv6.c +3 −9
  9. net/netfilter/ipvs/ip_vs_core.c +1 −1
  10. net/netfilter/nf_nat_core.c +16 −8
  11. net/netfilter/nfnetlink_acct.c +85 −0
  12. net/netfilter/xt_nfacct.c +4 −1
include/linux/netfilter/nfnetlink_acct.h+7−1
@@ -3,11 +3,17 @@ · 2 unmodified lines
33
44 #include <uapi/linux/netfilter/nfnetlink_acct.h>
55
6+enum {
7+ NFACCT_NO_QUOTA = -1,
8+ NFACCT_UNDERQUOTA,
9+ NFACCT_OVERQUOTA,
10+};
611
712 struct nf_acct;
813
914 struct nf_acct *nfnl_acct_find_get(const char *filter_name);
1015 void nfnl_acct_put(struct nf_acct *acct);
1116 void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct);
12−
17+extern int nfnl_acct_overquota(const struct sk_buff *skb,
18+ struct nf_acct *nfacct);
1319 #endif /* _NFNL_ACCT_H */
include/net/netfilter/nf_nat.h+2−0
@@ -48,6 +48,8 @@ unsigned int nf_nat_setup_info(struct nf_conn *ct, · 47 unmodified lines
4848 extern unsigned int nf_nat_alloc_null_binding(struct nf_conn *ct,
4949 unsigned int hooknum);
5050
51+struct nf_conn_nat *nf_ct_nat_ext_add(struct nf_conn *ct);
52+
5153 /* Is this tuple already taken? (not by us)*/
5254 int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
5355 const struct nf_conn *ignored_conntrack);
include/uapi/linux/netfilter/nfnetlink.h+2−0
@@ -20,6 +20,8 @@ enum nfnetlink_groups { · 19 unmodified lines
2020 #define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
2121 NFNLGRP_NFTABLES,
2222 #define NFNLGRP_NFTABLES NFNLGRP_NFTABLES
23+ NFNLGRP_ACCT_QUOTA,
24+#define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA
2325 __NFNLGRP_MAX,
2426 };
2527 #define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
include/uapi/linux/netfilter/nfnetlink_acct.h+9−0
@@ -10,15 +10,24 @@ enum nfnl_acct_msg_types { · 9 unmodified lines
1010 NFNL_MSG_ACCT_GET,
1111 NFNL_MSG_ACCT_GET_CTRZERO,
1212 NFNL_MSG_ACCT_DEL,
13+ NFNL_MSG_ACCT_OVERQUOTA,
1314 NFNL_MSG_ACCT_MAX
1415 };
1516
17+enum 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+
1623 enum nfnl_acct_type {
1724 NFACCT_UNSPEC,
1825 NFACCT_NAME,
1926 NFACCT_PKTS,
2027 NFACCT_BYTES,
2128 NFACCT_USE,
29+ NFACCT_FLAGS,
30+ NFACCT_QUOTA,
2231 __NFACCT_MAX
2332 };
2433 #define NFACCT_MAX (__NFACCT_MAX - 1)
net/ipv4/netfilter/iptable_nat.c+3−11
@@ -91,17 +91,9 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops, · 90 unmodified lines
9191 if (nf_ct_is_untracked(ct))
9292 return NF_ACCEPT;
9393
94− nat = nfct_nat(ct);
95− if (!nat) {
96− /* NAT module was loaded late. */
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− }
94+ nat = nf_ct_nat_ext_add(ct);
95+ if (nat == NULL)
96+ return NF_ACCEPT;
10597
10698 switch (ctinfo) {
10799 case IP_CT_RELATED:
net/ipv4/netfilter/nft_chain_nat_ipv4.c+3−9
@@ -48,15 +48,9 @@ static unsigned int nf_nat_fn(const struct nf_hook_ops *ops, · 47 unmodified lines
4848
4949 NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
5050
51− nat = nfct_nat(ct);
52− if (nat == NULL) {
53− /* Conntrack module was loaded late, can't add extension. */
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− }
51+ nat = nf_ct_nat_ext_add(ct);
52+ if (nat == NULL)
53+ return NF_ACCEPT;
6054
6155 switch (ctinfo) {
6256 case IP_CT_RELATED:
net/ipv6/netfilter/ip6table_nat.c+3−11
@@ -90,17 +90,9 @@ nf_nat_ipv6_fn(const struct nf_hook_ops *ops, · 89 unmodified lines
9090 if (nf_ct_is_untracked(ct))
9191 return NF_ACCEPT;
9292
93− nat = nfct_nat(ct);
94− if (!nat) {
95− /* NAT module was loaded late. */
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− }
93+ nat = nf_ct_nat_ext_add(ct);
94+ if (nat == NULL)
95+ return NF_ACCEPT;
10496
10597 switch (ctinfo) {
10698 case IP_CT_RELATED:
net/ipv6/netfilter/nft_chain_nat_ipv6.c+3−9
@@ -47,15 +47,9 @@ static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, · 46 unmodified lines
4747 if (ct == NULL || nf_ct_is_untracked(ct))
4848 return NF_ACCEPT;
4949
50− nat = nfct_nat(ct);
51− if (nat == NULL) {
52− /* Conntrack module was loaded late, can't add extension. */
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− }
50+ nat = nf_ct_nat_ext_add(ct);
51+ if (nat == NULL)
52+ return NF_ACCEPT;
5953
6054 switch (ctinfo) {
6155 case IP_CT_RELATED:
net/netfilter/ipvs/ip_vs_core.c+1−1
@@ -97,7 +97,7 @@ const char *ip_vs_proto_name(unsigned int proto) · 96 unmodified lines
9797 return "ICMPv6";
9898 #endif
9999 default:
100− sprintf(buf, "IP_%d", proto);
100+ sprintf(buf, "IP_%u", proto);
101101 return buf;
102102 }
103103 }
net/netfilter/nf_nat_core.c+16−8
@@ -358,6 +358,19 @@ out: · 357 unmodified lines
358358 rcu_read_unlock();
359359 }
360360
361+struct 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+}
372+EXPORT_SYMBOL_GPL(nf_ct_nat_ext_add);
373+
361374 unsigned int
362375 nf_nat_setup_info(struct nf_conn *ct,
363376 const struct nf_nat_range *range,
@@ -368,14 +381,9 @@ nf_nat_setup_info(struct nf_conn *ct, · 4 unmodified lines
368381 struct nf_conn_nat *nat;
369382
370383 /* nat helper or nfctnetlink also setup binding */
371− nat = nfct_nat(ct);
372− if (!nat) {
373− nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
374− if (nat == NULL) {
375− pr_debug("failed to add NAT extension\n");
376− return NF_ACCEPT;
377− }
378− }
384+ nat = nf_ct_nat_ext_add(ct);
385+ if (nat == NULL)
386+ return NF_ACCEPT;
379387
380388 NF_CT_ASSERT(maniptype == NF_NAT_MANIP_SRC ||
381389 maniptype == NF_NAT_MANIP_DST);
net/netfilter/nfnetlink_acct.c+85−0
@@ -32,18 +32,24 @@ static LIST_HEAD(nfnl_acct_list); · 31 unmodified lines
3232 struct nf_acct {
3333 atomic64_t pkts;
3434 atomic64_t bytes;
35+ unsigned long flags;
3536 struct list_head head;
3637 atomic_t refcnt;
3738 char name[NFACCT_NAME_MAX];
3839 struct rcu_head rcu_head;
40+ char data[0];
3941 };
4042
43+#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
44+
4145 static int
4246 nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
4347 const struct nlmsghdr *nlh, const struct nlattr * const tb[])
4448 {
4549 struct nf_acct *nfacct, *matching = NULL;
4650 char *acct_name;
51+ unsigned int size = 0;
52+ u32 flags = 0;
4753
4854 if (!tb[NFACCT_NAME])
4955 return -EINVAL;
@@ -68,15 +74,39 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, · 18 unmodified lines
6874 /* reset counters if you request a replacement. */
6975 atomic64_set(&matching->pkts, 0);
7076 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);
7181 return 0;
7282 }
7383 return -EBUSY;
7484 }
7585
7686 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);
77100 if (nfacct == NULL)
78101 return -ENOMEM;
79102
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+
80110 strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX);
81111
82112 if (tb[NFACCT_BYTES]) {
@@ -117,6 +147,9 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, · 34 unmodified lines
117147 if (type == NFNL_MSG_ACCT_GET_CTRZERO) {
118148 pkts = atomic64_xchg(&acct->pkts, 0);
119149 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);
120153 } else {
121154 pkts = atomic64_read(&acct->pkts);
122155 bytes = atomic64_read(&acct->bytes);
@@ -125,7 +158,13 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, · 2 unmodified lines
125158 nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes)) ||
126159 nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt))))
127160 goto nla_put_failure;
161+ if (acct->flags & NFACCT_F_QUOTA) {
162+ u64 *quota = (u64 *)acct->data;
128163
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+ }
129168 nlmsg_end(skb, nlh);
130169 return skb->len;
131170
@@ -270,6 +309,8 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = { · 138 unmodified lines
270309 [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 },
271310 [NFACCT_BYTES] = { .type = NLA_U64 },
272311 [NFACCT_PKTS] = { .type = NLA_U64 },
312+ [NFACCT_FLAGS] = { .type = NLA_U32 },
313+ [NFACCT_QUOTA] = { .type = NLA_U64 },
273314 };
274315
275316 static 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) · 60 unmodified lines
336377 }
337378 EXPORT_SYMBOL_GPL(nfnl_acct_update);
338379
380+static 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+
399+int 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+}
422+EXPORT_SYMBOL_GPL(nfnl_acct_overquota);
423+
339424 static int __init nfnl_acct_init(void)
340425 {
341426 int ret;
net/netfilter/xt_nfacct.c+4−1
@@ -21,11 +21,14 @@ MODULE_ALIAS("ip6t_nfacct"); · 20 unmodified lines
2121
2222 static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par)
2323 {
24+ int overquota;
2425 const struct xt_nfacct_match_info *info = par->targinfo;
2526
2627 nfnl_acct_update(skb, info->nfacct);
2728
28− return true;
29+ overquota = nfnl_acct_overquota(skb, info->nfacct);
30+
31+ return overquota == NFACCT_UNDERQUOTA ? false : true;
2932 }
3033
3134 static int