1/* Accouting handling for netfilter. */ 2 3/* 4 * (C) 2008 Krzysztof Piotr Oledzki <ole@ans.pl> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11#include <linux/netfilter.h> 12#include <linux/slab.h> 13#include <linux/kernel.h> 14#include <linux/moduleparam.h> 15 16#include <net/netfilter/nf_conntrack.h> 17#include <net/netfilter/nf_conntrack_extend.h> 18#include <net/netfilter/nf_conntrack_acct.h> 19 20static int nf_ct_acct __read_mostly; 21 22module_param_named(acct, nf_ct_acct, bool, 0644); 23MODULE_PARM_DESC(acct, "Enable connection tracking flow accounting."); 24 25#ifdef CONFIG_SYSCTL 26static struct ctl_table acct_sysctl_table[] = { 27 { 28 .procname = "nf_conntrack_acct", 29 .data = &init_net.ct.sysctl_acct, 30 .maxlen = sizeof(unsigned int), 31 .mode = 0644, 32 .proc_handler = proc_dointvec, 33 }, 34 {} 35}; 36#endif /* CONFIG_SYSCTL */ 37 38unsigned int 39seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir) 40{ 41 struct nf_conn_counter *acct; 42 43 acct = nf_conn_acct_find(ct); 44 if (!acct) 45 return 0; 46 47 return seq_printf(s, "packets=%llu bytes=%llu ", 48 (unsigned long long)acct[dir].packets, 49 (unsigned long long)acct[dir].bytes); 50}; 51EXPORT_SYMBOL_GPL(seq_print_acct); 52 53static struct nf_ct_ext_type acct_extend __read_mostly = { 54 .len = sizeof(struct nf_conn_counter[IP_CT_DIR_MAX]), 55 .align = __alignof__(struct nf_conn_counter[IP_CT_DIR_MAX]), 56 .id = NF_CT_EXT_ACCT, 57}; 58 59#ifdef CONFIG_SYSCTL 60static int nf_conntrack_acct_init_sysctl(struct net *net) 61{ 62 struct ctl_table *table; 63 64 table = kmemdup(acct_sysctl_table, sizeof(acct_sysctl_table), 65 GFP_KERNEL); 66 if (!table) 67 goto out; 68 69 table[0].data = &net->ct.sysctl_acct; 70 71 net->ct.acct_sysctl_header = register_net_sysctl_table(net, 72 nf_net_netfilter_sysctl_path, table); 73 if (!net->ct.acct_sysctl_header) { 74 printk(KERN_ERR "nf_conntrack_acct: can't register to sysctl.\n"); 75 goto out_register; 76 } 77 return 0; 78 79out_register: 80 kfree(table); 81out: 82 return -ENOMEM; 83} 84 85static void nf_conntrack_acct_fini_sysctl(struct net *net) 86{ 87 struct ctl_table *table; 88 89 table = net->ct.acct_sysctl_header->ctl_table_arg; 90 unregister_net_sysctl_table(net->ct.acct_sysctl_header); 91 kfree(table); 92} 93#else 94static int nf_conntrack_acct_init_sysctl(struct net *net) 95{ 96 return 0; 97} 98 99static void nf_conntrack_acct_fini_sysctl(struct net *net) 100{ 101} 102#endif 103 104int nf_conntrack_acct_init(struct net *net) 105{ 106 int ret; 107 108 net->ct.sysctl_acct = nf_ct_acct; 109 110 if (net_eq(net, &init_net)) { 111 ret = nf_ct_extend_register(&acct_extend); 112 if (ret < 0) { 113 printk(KERN_ERR "nf_conntrack_acct: Unable to register extension\n"); 114 goto out_extend_register; 115 } 116 } 117 118 ret = nf_conntrack_acct_init_sysctl(net); 119 if (ret < 0) 120 goto out_sysctl; 121 122 return 0; 123 124out_sysctl: 125 if (net_eq(net, &init_net)) 126 nf_ct_extend_unregister(&acct_extend); 127out_extend_register: 128 return ret; 129} 130 131void nf_conntrack_acct_fini(struct net *net) 132{ 133 nf_conntrack_acct_fini_sysctl(net); 134 if (net_eq(net, &init_net)) 135 nf_ct_extend_unregister(&acct_extend); 136} 137