158401572SKrzysztof Piotr Oledzki /* Accouting handling for netfilter. */
258401572SKrzysztof Piotr Oledzki 
358401572SKrzysztof Piotr Oledzki /*
458401572SKrzysztof Piotr Oledzki  * (C) 2008 Krzysztof Piotr Oledzki <ole@ans.pl>
558401572SKrzysztof Piotr Oledzki  *
658401572SKrzysztof Piotr Oledzki  * This program is free software; you can redistribute it and/or modify
758401572SKrzysztof Piotr Oledzki  * it under the terms of the GNU General Public License version 2 as
858401572SKrzysztof Piotr Oledzki  * published by the Free Software Foundation.
958401572SKrzysztof Piotr Oledzki  */
1058401572SKrzysztof Piotr Oledzki 
1158401572SKrzysztof Piotr Oledzki #include <linux/netfilter.h>
125a0e3ad6STejun Heo #include <linux/slab.h>
1358401572SKrzysztof Piotr Oledzki #include <linux/kernel.h>
1458401572SKrzysztof Piotr Oledzki #include <linux/moduleparam.h>
15bc3b2d7fSPaul Gortmaker #include <linux/export.h>
1658401572SKrzysztof Piotr Oledzki 
1758401572SKrzysztof Piotr Oledzki #include <net/netfilter/nf_conntrack.h>
1858401572SKrzysztof Piotr Oledzki #include <net/netfilter/nf_conntrack_extend.h>
1958401572SKrzysztof Piotr Oledzki #include <net/netfilter/nf_conntrack_acct.h>
2058401572SKrzysztof Piotr Oledzki 
21d70a011dSTim Gardner static int nf_ct_acct __read_mostly;
2258401572SKrzysztof Piotr Oledzki 
2358401572SKrzysztof Piotr Oledzki module_param_named(acct, nf_ct_acct, bool, 0644);
2458401572SKrzysztof Piotr Oledzki MODULE_PARM_DESC(acct, "Enable connection tracking flow accounting.");
2558401572SKrzysztof Piotr Oledzki 
2658401572SKrzysztof Piotr Oledzki #ifdef CONFIG_SYSCTL
2758401572SKrzysztof Piotr Oledzki static struct ctl_table acct_sysctl_table[] = {
2858401572SKrzysztof Piotr Oledzki 	{
2958401572SKrzysztof Piotr Oledzki 		.procname	= "nf_conntrack_acct",
30d716a4dfSAlexey Dobriyan 		.data		= &init_net.ct.sysctl_acct,
3158401572SKrzysztof Piotr Oledzki 		.maxlen		= sizeof(unsigned int),
3258401572SKrzysztof Piotr Oledzki 		.mode		= 0644,
336d9f239aSAlexey Dobriyan 		.proc_handler	= proc_dointvec,
3458401572SKrzysztof Piotr Oledzki 	},
3558401572SKrzysztof Piotr Oledzki 	{}
3658401572SKrzysztof Piotr Oledzki };
3758401572SKrzysztof Piotr Oledzki #endif /* CONFIG_SYSCTL */
3858401572SKrzysztof Piotr Oledzki 
3958401572SKrzysztof Piotr Oledzki unsigned int
4058401572SKrzysztof Piotr Oledzki seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir)
4158401572SKrzysztof Piotr Oledzki {
4258401572SKrzysztof Piotr Oledzki 	struct nf_conn_counter *acct;
4358401572SKrzysztof Piotr Oledzki 
4458401572SKrzysztof Piotr Oledzki 	acct = nf_conn_acct_find(ct);
4558401572SKrzysztof Piotr Oledzki 	if (!acct)
4658401572SKrzysztof Piotr Oledzki 		return 0;
4758401572SKrzysztof Piotr Oledzki 
4858401572SKrzysztof Piotr Oledzki 	return seq_printf(s, "packets=%llu bytes=%llu ",
4958401572SKrzysztof Piotr Oledzki 			  (unsigned long long)acct[dir].packets,
5058401572SKrzysztof Piotr Oledzki 			  (unsigned long long)acct[dir].bytes);
5158401572SKrzysztof Piotr Oledzki };
5258401572SKrzysztof Piotr Oledzki EXPORT_SYMBOL_GPL(seq_print_acct);
5358401572SKrzysztof Piotr Oledzki 
5458401572SKrzysztof Piotr Oledzki static struct nf_ct_ext_type acct_extend __read_mostly = {
5558401572SKrzysztof Piotr Oledzki 	.len	= sizeof(struct nf_conn_counter[IP_CT_DIR_MAX]),
5658401572SKrzysztof Piotr Oledzki 	.align	= __alignof__(struct nf_conn_counter[IP_CT_DIR_MAX]),
5758401572SKrzysztof Piotr Oledzki 	.id	= NF_CT_EXT_ACCT,
5858401572SKrzysztof Piotr Oledzki };
5958401572SKrzysztof Piotr Oledzki 
60d716a4dfSAlexey Dobriyan #ifdef CONFIG_SYSCTL
61d716a4dfSAlexey Dobriyan static int nf_conntrack_acct_init_sysctl(struct net *net)
62d716a4dfSAlexey Dobriyan {
63d716a4dfSAlexey Dobriyan 	struct ctl_table *table;
64d716a4dfSAlexey Dobriyan 
65d716a4dfSAlexey Dobriyan 	table = kmemdup(acct_sysctl_table, sizeof(acct_sysctl_table),
66d716a4dfSAlexey Dobriyan 			GFP_KERNEL);
67d716a4dfSAlexey Dobriyan 	if (!table)
68d716a4dfSAlexey Dobriyan 		goto out;
69d716a4dfSAlexey Dobriyan 
70d716a4dfSAlexey Dobriyan 	table[0].data = &net->ct.sysctl_acct;
71d716a4dfSAlexey Dobriyan 
72d716a4dfSAlexey Dobriyan 	net->ct.acct_sysctl_header = register_net_sysctl_table(net,
73d716a4dfSAlexey Dobriyan 			nf_net_netfilter_sysctl_path, table);
74d716a4dfSAlexey Dobriyan 	if (!net->ct.acct_sysctl_header) {
75d716a4dfSAlexey Dobriyan 		printk(KERN_ERR "nf_conntrack_acct: can't register to sysctl.\n");
76d716a4dfSAlexey Dobriyan 		goto out_register;
77d716a4dfSAlexey Dobriyan 	}
78d716a4dfSAlexey Dobriyan 	return 0;
79d716a4dfSAlexey Dobriyan 
80d716a4dfSAlexey Dobriyan out_register:
81d716a4dfSAlexey Dobriyan 	kfree(table);
82d716a4dfSAlexey Dobriyan out:
83d716a4dfSAlexey Dobriyan 	return -ENOMEM;
84d716a4dfSAlexey Dobriyan }
85d716a4dfSAlexey Dobriyan 
86d716a4dfSAlexey Dobriyan static void nf_conntrack_acct_fini_sysctl(struct net *net)
87d716a4dfSAlexey Dobriyan {
88d716a4dfSAlexey Dobriyan 	struct ctl_table *table;
89d716a4dfSAlexey Dobriyan 
90d716a4dfSAlexey Dobriyan 	table = net->ct.acct_sysctl_header->ctl_table_arg;
91d716a4dfSAlexey Dobriyan 	unregister_net_sysctl_table(net->ct.acct_sysctl_header);
92d716a4dfSAlexey Dobriyan 	kfree(table);
93d716a4dfSAlexey Dobriyan }
94d716a4dfSAlexey Dobriyan #else
95d716a4dfSAlexey Dobriyan static int nf_conntrack_acct_init_sysctl(struct net *net)
96d716a4dfSAlexey Dobriyan {
97d716a4dfSAlexey Dobriyan 	return 0;
98d716a4dfSAlexey Dobriyan }
99d716a4dfSAlexey Dobriyan 
100d716a4dfSAlexey Dobriyan static void nf_conntrack_acct_fini_sysctl(struct net *net)
101d716a4dfSAlexey Dobriyan {
102d716a4dfSAlexey Dobriyan }
103d716a4dfSAlexey Dobriyan #endif
104d716a4dfSAlexey Dobriyan 
105d716a4dfSAlexey Dobriyan int nf_conntrack_acct_init(struct net *net)
10658401572SKrzysztof Piotr Oledzki {
10758401572SKrzysztof Piotr Oledzki 	int ret;
10858401572SKrzysztof Piotr Oledzki 
109d716a4dfSAlexey Dobriyan 	net->ct.sysctl_acct = nf_ct_acct;
110d716a4dfSAlexey Dobriyan 
111d716a4dfSAlexey Dobriyan 	if (net_eq(net, &init_net)) {
11258401572SKrzysztof Piotr Oledzki 		ret = nf_ct_extend_register(&acct_extend);
11358401572SKrzysztof Piotr Oledzki 		if (ret < 0) {
11458401572SKrzysztof Piotr Oledzki 			printk(KERN_ERR "nf_conntrack_acct: Unable to register extension\n");
115d716a4dfSAlexey Dobriyan 			goto out_extend_register;
116d716a4dfSAlexey Dobriyan 		}
117d716a4dfSAlexey Dobriyan 	}
118d716a4dfSAlexey Dobriyan 
119d716a4dfSAlexey Dobriyan 	ret = nf_conntrack_acct_init_sysctl(net);
120d716a4dfSAlexey Dobriyan 	if (ret < 0)
121d716a4dfSAlexey Dobriyan 		goto out_sysctl;
122d716a4dfSAlexey Dobriyan 
123d716a4dfSAlexey Dobriyan 	return 0;
124d716a4dfSAlexey Dobriyan 
125d716a4dfSAlexey Dobriyan out_sysctl:
126d716a4dfSAlexey Dobriyan 	if (net_eq(net, &init_net))
127d716a4dfSAlexey Dobriyan 		nf_ct_extend_unregister(&acct_extend);
128d716a4dfSAlexey Dobriyan out_extend_register:
12958401572SKrzysztof Piotr Oledzki 	return ret;
13058401572SKrzysztof Piotr Oledzki }
13158401572SKrzysztof Piotr Oledzki 
132d716a4dfSAlexey Dobriyan void nf_conntrack_acct_fini(struct net *net)
13358401572SKrzysztof Piotr Oledzki {
134d716a4dfSAlexey Dobriyan 	nf_conntrack_acct_fini_sysctl(net);
135d716a4dfSAlexey Dobriyan 	if (net_eq(net, &init_net))
13658401572SKrzysztof Piotr Oledzki 		nf_ct_extend_unregister(&acct_extend);
13758401572SKrzysztof Piotr Oledzki }
138