Oct 28, 2006, 9:48 AM
Post #3 of 22
(9508 views)
Permalink
On Thu, 26 Oct 2006, Patrick McHardy wrote:
> Krzysztof Oledzki wrote:
>> Hello,
>>
>> It seems there is something wrong with connbytes and 64bit conters.
>>
>> The "iptables" manual mention that counters are 64bit, so there should
>> be no problem with overflows, but it seems it might not be true. My
>> firewall puts long living ftp & http connections to a different TC class
>> when they reach 256MB, but aftear they reach 4GB (probably) they go back
>> to the default class, with no speed limit.
>>
>> After some researches I found that ip_conntrack_counter structure
>> defined in nf_conntrack_common.h uses u_int32_t. I always thought that
>> netfilter has 64bit counters, hasn't it? And I'm quite sure it used to
>> work when I set up my firewall, about 1 year ago. Stange...
>
>
> It was changed to save some memory in struct ip_conntrack.
> The idea was mainly that its only used for ctnetlink and
> it is possible to send events before overflow. Obviously,
> this wasn't true (besides the fact that events are unreliable).
> Not sure what we should do about it ..
How about attached (and inlined for easy review) patch?
[NETFILTER] Reimplementation of 64bit counters for bytes/packets accounting
Initially netfilter has had 64bit counters for conntrack-based accounting, but
it was changed in 2.6.14 to save memory. Unfortunately in-kernel 64bit counters are
still required, for example for "connbytes" extension. Add possibility to choose
between 32 and 64bits but keep default 32bit counters.
Signed-off-by: Krzysztof Piotr Oledzki <ole@ans.pl>
diff -Nur linux-2.6.19-rc3-orig/include/linux/netfilter/nf_conntrack_common.h linux-2.6.19-rc3/include/linux/netfilter/nf_conntrack_common.h
--- linux-2.6.19-rc3-orig/include/linux/netfilter/nf_conntrack_common.h 2006-10-24 01:02:02.000000000 +0200
+++ linux-2.6.19-rc3/include/linux/netfilter/nf_conntrack_common.h 2006-10-28 17:42:48.000000000 +0200
@@ -139,8 +139,13 @@
#ifdef __KERNEL__
struct ip_conntrack_counter
{
+#if defined(CONFIG_IP_NF_CT_ACCT_64BIT_COUNTERS) || defined(CONFIG_NF_CT_ACCT_64BIT_COUNTERS)
+ u_int64_t packets;
+ u_int64_t bytes;
+#else
u_int32_t packets;
u_int32_t bytes;
+#endif
};
struct ip_conntrack_stat
diff -Nur linux-2.6.19-rc3-orig/include/linux/netfilter/nfnetlink_conntrack.h linux-2.6.19-rc3/include/linux/netfilter/nfnetlink_conntrack.h
--- linux-2.6.19-rc3-orig/include/linux/netfilter/nfnetlink_conntrack.h 2006-10-24 01:02:02.000000000 +0200
+++ linux-2.6.19-rc3/include/linux/netfilter/nfnetlink_conntrack.h 2006-10-25 14:55:19.000000000 +0200
@@ -89,8 +89,8 @@
enum ctattr_counters {
CTA_COUNTERS_UNSPEC,
- CTA_COUNTERS_PACKETS, /* old 64bit counters */
- CTA_COUNTERS_BYTES, /* old 64bit counters */
+ CTA_COUNTERS_PACKETS, /* optional 64bit counters */
+ CTA_COUNTERS_BYTES, /* optional 64bit counters */
CTA_COUNTERS32_PACKETS,
CTA_COUNTERS32_BYTES,
__CTA_COUNTERS_MAX
diff -Nur linux-2.6.19-rc3-orig/net/ipv4/netfilter/Kconfig linux-2.6.19-rc3/net/ipv4/netfilter/Kconfig
--- linux-2.6.19-rc3-orig/net/ipv4/netfilter/Kconfig 2006-10-24 01:02:02.000000000 +0200
+++ linux-2.6.19-rc3/net/ipv4/netfilter/Kconfig 2006-10-28 18:44:16.000000000 +0200
@@ -46,6 +46,21 @@
If unsure, say `N'.
+config IP_NF_CT_ACCT_64BIT_COUNTERS
+ bool 'Enable 64bit counters for conntrack-based accounting'
+ depends on IP_NF_CT_ACCT
+ default n
+ help
+ Use 64 bit counters for bytes/packets accounting instead of default 32.
+
+ This will make every connection entry larger by 16 bytes, enlarging
+ it by about 5%.
+
+ Say Y if you have plenty of RAM and want to be able to detect
+ long-lived connections, using for example "connbytes" extension.
+
+ If unsure, say N.
+
config IP_NF_CONNTRACK_MARK
bool 'Connection mark tracking support'
depends on IP_NF_CONNTRACK
diff -Nur linux-2.6.19-rc3-orig/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.19-rc3/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.6.19-rc3-orig/net/ipv4/netfilter/ip_conntrack_core.c 2006-10-24 01:02:02.000000000 +0200
+++ linux-2.6.19-rc3/net/ipv4/netfilter/ip_conntrack_core.c 2006-10-28 17:44:28.000000000 +0200
@@ -1148,9 +1148,15 @@
ct->counters[CTINFO2DIR(ctinfo)].packets++;
ct->counters[CTINFO2DIR(ctinfo)].bytes +=
ntohs(skb->nh.iph->tot_len);
+#ifdef CONFIG_IP_NF_CT_ACCT_64BIT_COUNTERS
+ if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x8000000000000000LL)
+ || (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x8000000000000000LL))
+ event |= IPCT_COUNTER_FILLING;
+#else
if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x80000000)
|| (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x80000000))
event |= IPCT_COUNTER_FILLING;
+#endif
}
#endif
diff -Nur linux-2.6.19-rc3-orig/net/ipv4/netfilter/ip_conntrack_netlink.c linux-2.6.19-rc3/net/ipv4/netfilter/ip_conntrack_netlink.c
--- linux-2.6.19-rc3-orig/net/ipv4/netfilter/ip_conntrack_netlink.c 2006-10-24 01:02:02.000000000 +0200
+++ linux-2.6.19-rc3/net/ipv4/netfilter/ip_conntrack_netlink.c 2006-10-28 18:23:06.000000000 +0200
@@ -185,6 +185,15 @@
{
enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
struct nfattr *nest_count = NFA_NEST(skb, type);
+#ifdef CONFIG_IP_NF_CT_ACCT_64BIT_COUNTERS
+ __be64 tmp;
+
+ tmp = cpu_to_be64(ct->counters[dir].packets);
+ NFA_PUT(skb, CTA_COUNTERS_PACKETS, sizeof(__be64), &tmp);
+
+ tmp = cpu_to_be64(ct->counters[dir].bytes);
+ NFA_PUT(skb, CTA_COUNTERS_BYTES, sizeof(__be64), &tmp);
+#else
__be32 tmp;
tmp = htonl(ct->counters[dir].packets);
@@ -192,6 +201,7 @@
tmp = htonl(ct->counters[dir].bytes);
NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp);
+#endif
NFA_NEST_END(skb, nest_count);
diff -Nur linux-2.6.19-rc3-orig/net/netfilter/Kconfig linux-2.6.19-rc3/net/netfilter/Kconfig
--- linux-2.6.19-rc3-orig/net/netfilter/Kconfig 2006-10-24 01:02:02.000000000 +0200
+++ linux-2.6.19-rc3/net/netfilter/Kconfig 2006-10-28 18:43:54.000000000 +0200
@@ -51,6 +51,21 @@
If unsure, say `N'.
+config NF_CT_ACCT_64BIT_COUNTERS
+ bool 'Enable 64bit counters for conntrack-based accounting'
+ depends on NF_CT_ACCT
+ default n
+ help
+ Use 64 bit counters for bytes/packets accounting instead of default 32.
+
+ This will make every connection entry larger by 16 bytes, enlarging
+ it by about 5%.
+
+ Say Y if you have plenty of RAM and want to be able to detect
+ long-lived connections, using for example "connbytes" extension.
+
+ If unsure, say N.
+
config NF_CONNTRACK_MARK
bool 'Connection mark tracking support'
depends on NF_CONNTRACK
diff -Nur linux-2.6.19-rc3-orig/net/netfilter/nf_conntrack_core.c linux-2.6.19-rc3/net/netfilter/nf_conntrack_core.c
--- linux-2.6.19-rc3-orig/net/netfilter/nf_conntrack_core.c 2006-10-24 01:02:02.000000000 +0200
+++ linux-2.6.19-rc3/net/netfilter/nf_conntrack_core.c 2006-10-28 17:44:11.000000000 +0200
@@ -1412,9 +1412,15 @@
ct->counters[CTINFO2DIR(ctinfo)].packets++;
ct->counters[CTINFO2DIR(ctinfo)].bytes +=
skb->len - (unsigned int)(skb->nh.raw - skb->data);
+#ifdef CONFIG_NF_CT_ACCT_64BIT_COUNTERS
+ if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x8000000000000000LL)
+ || (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x8000000000000000LL))
+ event |= IPCT_COUNTER_FILLING;
+#else
if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x80000000)
|| (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x80000000))
event |= IPCT_COUNTER_FILLING;
+#endif
}
#endif
diff -Nur linux-2.6.19-rc3-orig/net/netfilter/nf_conntrack_netlink.c linux-2.6.19-rc3/net/netfilter/nf_conntrack_netlink.c
--- linux-2.6.19-rc3-orig/net/netfilter/nf_conntrack_netlink.c 2006-10-24 01:02:02.000000000 +0200
+++ linux-2.6.19-rc3/net/netfilter/nf_conntrack_netlink.c 2006-10-28 18:24:12.000000000 +0200
@@ -194,13 +194,23 @@
{
enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
struct nfattr *nest_count = NFA_NEST(skb, type);
- u_int32_t tmp;
+#ifdef CONFIG_NF_CT_ACCT_64BIT_COUNTERS
+ __be64 tmp;
+
+ tmp = cpu_to_be64(ct->counters[dir].packets);
+ NFA_PUT(skb, CTA_COUNTERS_PACKETS, sizeof(__be64), &tmp);
+
+ tmp = cpu_to_be64(ct->counters[dir].bytes);
+ NFA_PUT(skb, CTA_COUNTERS_BYTES, sizeof(__be64), &tmp);
+#else
+ __be32 tmp;
tmp = htonl(ct->counters[dir].packets);
- NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
+ NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(__be32), &tmp);
tmp = htonl(ct->counters[dir].bytes);
- NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);
+ NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp);
+#endif
NFA_NEST_END(skb, nest_count);
Best regards,
Krzysztof Olêdzki