Commit fd8bcd00 authored by Harald Welte's avatar Harald Welte Committed by David S. Miller

[NETFILTER]: Connection based accounting

This patch adds a config option to enable per-flow packet and byte
accounting to ip_conntrack. 
Signed-off-by: default avatarHarald Welte <laforge@netfilter.org>
Signed-off-by: default avatarDavid S. Miller <davem@redhat.com>
parent 4cc4f57c
...@@ -156,6 +156,12 @@ struct ip_conntrack_expect ...@@ -156,6 +156,12 @@ struct ip_conntrack_expect
union ip_conntrack_expect_help help; union ip_conntrack_expect_help help;
}; };
struct ip_conntrack_counter
{
u_int64_t packets;
u_int64_t bytes;
};
struct ip_conntrack_helper; struct ip_conntrack_helper;
struct ip_conntrack struct ip_conntrack
...@@ -173,6 +179,11 @@ struct ip_conntrack ...@@ -173,6 +179,11 @@ struct ip_conntrack
/* Timer function; drops refcnt when it goes off. */ /* Timer function; drops refcnt when it goes off. */
struct timer_list timeout; struct timer_list timeout;
#ifdef CONFIG_IP_NF_CT_ACCT
/* Accounting Information (same cache line as other written members) */
struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
#endif
/* If we're expecting another related connection, this will be /* If we're expecting another related connection, this will be
in expected linked list */ in expected linked list */
struct list_head sibling_list; struct list_head sibling_list;
...@@ -245,8 +256,10 @@ extern int invert_tuplepr(struct ip_conntrack_tuple *inverse, ...@@ -245,8 +256,10 @@ extern int invert_tuplepr(struct ip_conntrack_tuple *inverse,
const struct ip_conntrack_tuple *orig); const struct ip_conntrack_tuple *orig);
/* Refresh conntrack for this many jiffies */ /* Refresh conntrack for this many jiffies */
extern void ip_ct_refresh(struct ip_conntrack *ct, extern void ip_ct_refresh_acct(struct ip_conntrack *ct,
unsigned long extra_jiffies); enum ip_conntrack_info ctinfo,
const struct sk_buff *skb,
unsigned long extra_jiffies);
/* These are for NAT. Icky. */ /* These are for NAT. Icky. */
/* Call me when a conntrack is destroyed. */ /* Call me when a conntrack is destroyed. */
......
...@@ -628,5 +628,9 @@ config IP_NF_MATCH_REALM ...@@ -628,5 +628,9 @@ config IP_NF_MATCH_REALM
If you want to compile it as a module, say M here and read If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say `N'. Documentation/modules.txt. If unsure, say `N'.
config IP_NF_CT_ACCT
bool "Connection tracking flow accounting"
depends on IP_NF_CONNTRACK
endmenu endmenu
...@@ -59,7 +59,7 @@ static int help(struct sk_buff *skb, ...@@ -59,7 +59,7 @@ static int help(struct sk_buff *skb,
/* increase the UDP timeout of the master connection as replies from /* increase the UDP timeout of the master connection as replies from
* Amanda clients to the server can be quite delayed */ * Amanda clients to the server can be quite delayed */
ip_ct_refresh(ct, master_timeout * HZ); ip_ct_refresh_acct(ct, ctinfo, NULL, master_timeout * HZ);
/* No data? */ /* No data? */
dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr); dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr);
......
...@@ -1165,21 +1165,39 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) ...@@ -1165,21 +1165,39 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
synchronize_net(); synchronize_net();
} }
/* Refresh conntrack for this many jiffies. */ static inline void ct_add_counters(struct ip_conntrack *ct,
void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies) enum ip_conntrack_info ctinfo,
const struct sk_buff *skb)
{
#ifdef CONFIG_IP_NF_CT_ACCT
if (skb) {
ct->counters[CTINFO2DIR(ctinfo)].packets++;
ct->counters[CTINFO2DIR(ctinfo)].bytes +=
ntohs(skb->nh.iph->tot_len);
}
#endif
}
/* Refresh conntrack for this many jiffies and do accounting (if skb != NULL) */
void ip_ct_refresh_acct(struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo,
const struct sk_buff *skb,
unsigned long extra_jiffies)
{ {
IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
/* If not in hash table, timer will not be active yet */ /* If not in hash table, timer will not be active yet */
if (!is_confirmed(ct)) if (!is_confirmed(ct)) {
ct->timeout.expires = extra_jiffies; ct->timeout.expires = extra_jiffies;
else { ct_add_counters(ct, ctinfo, skb);
} else {
WRITE_LOCK(&ip_conntrack_lock); WRITE_LOCK(&ip_conntrack_lock);
/* Need del_timer for race avoidance (may already be dying). */ /* Need del_timer for race avoidance (may already be dying). */
if (del_timer(&ct->timeout)) { if (del_timer(&ct->timeout)) {
ct->timeout.expires = jiffies + extra_jiffies; ct->timeout.expires = jiffies + extra_jiffies;
add_timer(&ct->timeout); add_timer(&ct->timeout);
} }
ct_add_counters(ct, ctinfo, skb);
WRITE_UNLOCK(&ip_conntrack_lock); WRITE_UNLOCK(&ip_conntrack_lock);
} }
} }
......
...@@ -50,9 +50,9 @@ static unsigned int generic_print_conntrack(char *buffer, ...@@ -50,9 +50,9 @@ static unsigned int generic_print_conntrack(char *buffer,
/* Returns verdict for packet, or -1 for invalid. */ /* Returns verdict for packet, or -1 for invalid. */
static int packet(struct ip_conntrack *conntrack, static int packet(struct ip_conntrack *conntrack,
const struct sk_buff *skb, const struct sk_buff *skb,
enum ip_conntrack_info conntrackinfo) enum ip_conntrack_info ctinfo)
{ {
ip_ct_refresh(conntrack, ip_ct_generic_timeout); ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_generic_timeout);
return NF_ACCEPT; return NF_ACCEPT;
} }
......
...@@ -94,7 +94,7 @@ static int icmp_packet(struct ip_conntrack *ct, ...@@ -94,7 +94,7 @@ static int icmp_packet(struct ip_conntrack *ct,
ct->timeout.function((unsigned long)ct); ct->timeout.function((unsigned long)ct);
} else { } else {
atomic_inc(&ct->proto.icmp.count); atomic_inc(&ct->proto.icmp.count);
ip_ct_refresh(ct, ip_ct_icmp_timeout); ip_ct_refresh_acct(ct, ctinfo, skb, ip_ct_icmp_timeout);
} }
return NF_ACCEPT; return NF_ACCEPT;
......
...@@ -225,7 +225,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, ...@@ -225,7 +225,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
set_bit(IPS_ASSURED_BIT, &conntrack->status); set_bit(IPS_ASSURED_BIT, &conntrack->status);
out: WRITE_UNLOCK(&tcp_lock); out: WRITE_UNLOCK(&tcp_lock);
ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]); ip_ct_refresh_acct(conntrack, ctinfo, skb, *tcp_timeouts[newconntrack]);
return NF_ACCEPT; return NF_ACCEPT;
} }
......
...@@ -60,16 +60,17 @@ static unsigned int udp_print_conntrack(char *buffer, ...@@ -60,16 +60,17 @@ static unsigned int udp_print_conntrack(char *buffer,
/* Returns verdict for packet, and may modify conntracktype */ /* Returns verdict for packet, and may modify conntracktype */
static int udp_packet(struct ip_conntrack *conntrack, static int udp_packet(struct ip_conntrack *conntrack,
const struct sk_buff *skb, const struct sk_buff *skb,
enum ip_conntrack_info conntrackinfo) enum ip_conntrack_info ctinfo)
{ {
/* If we've seen traffic both ways, this is some kind of UDP /* If we've seen traffic both ways, this is some kind of UDP
stream. Extend timeout. */ stream. Extend timeout. */
if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream); ip_ct_refresh_acct(conntrack, ctinfo, skb,
ip_ct_udp_timeout_stream);
/* Also, more likely to be important, and not a probe */ /* Also, more likely to be important, and not a probe */
set_bit(IPS_ASSURED_BIT, &conntrack->status); set_bit(IPS_ASSURED_BIT, &conntrack->status);
} else } else
ip_ct_refresh(conntrack, ip_ct_udp_timeout); ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_udp_timeout);
return NF_ACCEPT; return NF_ACCEPT;
} }
......
...@@ -83,6 +83,17 @@ print_expect(char *buffer, const struct ip_conntrack_expect *expect) ...@@ -83,6 +83,17 @@ print_expect(char *buffer, const struct ip_conntrack_expect *expect)
return len; return len;
} }
#ifdef CONFIG_IP_NF_CT_ACCT
static unsigned int
print_counters(char *buffer, struct ip_conntrack_counter *counter)
{
return sprintf(buffer, "packets=%llu bytes=%llu ",
counter->packets, counter->bytes);
}
#else
#define print_counters(x, y) 0
#endif
static unsigned int static unsigned int
print_conntrack(char *buffer, struct ip_conntrack *conntrack) print_conntrack(char *buffer, struct ip_conntrack *conntrack)
{ {
...@@ -102,11 +113,15 @@ print_conntrack(char *buffer, struct ip_conntrack *conntrack) ...@@ -102,11 +113,15 @@ print_conntrack(char *buffer, struct ip_conntrack *conntrack)
len += print_tuple(buffer + len, len += print_tuple(buffer + len,
&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
proto); proto);
len += print_counters(buffer + len,
&conntrack->counters[IP_CT_DIR_ORIGINAL]);
if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status))) if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
len += sprintf(buffer + len, "[UNREPLIED] "); len += sprintf(buffer + len, "[UNREPLIED] ");
len += print_tuple(buffer + len, len += print_tuple(buffer + len,
&conntrack->tuplehash[IP_CT_DIR_REPLY].tuple, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
proto); proto);
len += print_counters(buffer + len,
&conntrack->counters[IP_CT_DIR_REPLY]);
if (test_bit(IPS_ASSURED_BIT, &conntrack->status)) if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
len += sprintf(buffer + len, "[ASSURED] "); len += sprintf(buffer + len, "[ASSURED] ");
len += sprintf(buffer + len, "use=%u ", len += sprintf(buffer + len, "use=%u ",
...@@ -638,7 +653,7 @@ EXPORT_SYMBOL(need_ip_conntrack); ...@@ -638,7 +653,7 @@ EXPORT_SYMBOL(need_ip_conntrack);
EXPORT_SYMBOL(ip_conntrack_helper_register); EXPORT_SYMBOL(ip_conntrack_helper_register);
EXPORT_SYMBOL(ip_conntrack_helper_unregister); EXPORT_SYMBOL(ip_conntrack_helper_unregister);
EXPORT_SYMBOL(ip_ct_selective_cleanup); EXPORT_SYMBOL(ip_ct_selective_cleanup);
EXPORT_SYMBOL(ip_ct_refresh); EXPORT_SYMBOL(ip_ct_refresh_acct);
EXPORT_SYMBOL(ip_ct_find_proto); EXPORT_SYMBOL(ip_ct_find_proto);
EXPORT_SYMBOL(__ip_ct_find_proto); EXPORT_SYMBOL(__ip_ct_find_proto);
EXPORT_SYMBOL(ip_ct_find_helper); EXPORT_SYMBOL(ip_ct_find_helper);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment