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