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