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#include <linux/export.h> 16 17#include <net/netfilter/nf_conntrack.h> 18#include <net/netfilter/nf_conntrack_extend.h> 19#include <net/netfilter/nf_conntrack_acct.h> 20 21static bool nf_ct_acct __read_mostly; 22 23module_param_named(acct, nf_ct_acct, bool, 0644); 24MODULE_PARM_DESC(acct, "Enable connection tracking flow accounting."); 25 26#ifdef CONFIG_SYSCTL 27static struct ctl_table acct_sysctl_table[] = { 28 { 29 .procname = "nf_conntrack_acct", 30 .data = &init_net.ct.sysctl_acct, 31 .maxlen = sizeof(unsigned int), 32 .mode = 0644, 33 .proc_handler = proc_dointvec, 34 }, 35 {} 36}; 37#endif /* CONFIG_SYSCTL */ 38 39unsigned int 40seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir) 41{ 42 struct nf_conn_acct *acct; 43 struct nf_conn_counter *counter; 44 45 acct = nf_conn_acct_find(ct); 46 if (!acct) 47 return 0; 48 49 counter = acct->counter; 50 seq_printf(s, "packets=%llu bytes=%llu ", 51 (unsigned long long)atomic64_read(&counter[dir].packets), 52 (unsigned long long)atomic64_read(&counter[dir].bytes)); 53 54 return 0; 55}; 56EXPORT_SYMBOL_GPL(seq_print_acct); 57 58static struct nf_ct_ext_type acct_extend __read_mostly = { 59 .len = sizeof(struct nf_conn_acct), 60 .align = __alignof__(struct nf_conn_acct), 61 .id = NF_CT_EXT_ACCT, 62}; 63 64#ifdef CONFIG_SYSCTL 65static int nf_conntrack_acct_init_sysctl(struct net *net) 66{ 67 struct ctl_table *table; 68 69 table = kmemdup(acct_sysctl_table, sizeof(acct_sysctl_table), 70 GFP_KERNEL); 71 if (!table) 72 goto out; 73 74 table[0].data = &net->ct.sysctl_acct; 75 76 /* Don't export sysctls to unprivileged users */ 77 if (net->user_ns != &init_user_ns) 78 table[0].procname = NULL; 79 80 net->ct.acct_sysctl_header = register_net_sysctl(net, "net/netfilter", 81 table); 82 if (!net->ct.acct_sysctl_header) { 83 printk(KERN_ERR "nf_conntrack_acct: can't register to sysctl.\n"); 84 goto out_register; 85 } 86 return 0; 87 88out_register: 89 kfree(table); 90out: 91 return -ENOMEM; 92} 93 94static void nf_conntrack_acct_fini_sysctl(struct net *net) 95{ 96 struct ctl_table *table; 97 98 table = net->ct.acct_sysctl_header->ctl_table_arg; 99 unregister_net_sysctl_table(net->ct.acct_sysctl_header); 100 kfree(table); 101} 102#else 103static int nf_conntrack_acct_init_sysctl(struct net *net) 104{ 105 return 0; 106} 107 108static void nf_conntrack_acct_fini_sysctl(struct net *net) 109{ 110} 111#endif 112 113int nf_conntrack_acct_pernet_init(struct net *net) 114{ 115 net->ct.sysctl_acct = nf_ct_acct; 116 return nf_conntrack_acct_init_sysctl(net); 117} 118 119void nf_conntrack_acct_pernet_fini(struct net *net) 120{ 121 nf_conntrack_acct_fini_sysctl(net); 122} 123 124int nf_conntrack_acct_init(void) 125{ 126 int ret = nf_ct_extend_register(&acct_extend); 127 if (ret < 0) 128 pr_err("nf_conntrack_acct: Unable to register extension\n"); 129 return ret; 130} 131 132void nf_conntrack_acct_fini(void) 133{ 134 nf_ct_extend_unregister(&acct_extend); 135} 136