Skip to content
Snippets Groups Projects
tcp_metrics.c 27 KiB
Newer Older
  • Learn to ignore specific revisions
  • static unsigned int tcpmhash_entries;
    
    static int __init set_tcpmhash_entries(char *str)
    {
    	ssize_t ret;
    
    	if (!str)
    		return 0;
    
    
    	ret = kstrtouint(str, 0, &tcpmhash_entries);
    
    	if (ret)
    		return 0;
    
    	return 1;
    }
    __setup("tcpmhash_entries=", set_tcpmhash_entries);
    
    static int __net_init tcp_net_metrics_init(struct net *net)
    {
    
    	size_t size;
    	unsigned int slots;
    
    
    	slots = tcpmhash_entries;
    	if (!slots) {
    		if (totalram_pages >= 128 * 1024)
    			slots = 16 * 1024;
    		else
    			slots = 8 * 1024;
    	}
    
    
    	net->ipv4.tcp_metrics_hash_log = order_base_2(slots);
    	size = sizeof(struct tcpm_hash_bucket) << net->ipv4.tcp_metrics_hash_log;
    
    	net->ipv4.tcp_metrics_hash = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
    	if (!net->ipv4.tcp_metrics_hash)
    		net->ipv4.tcp_metrics_hash = vzalloc(size);
    
    
    	if (!net->ipv4.tcp_metrics_hash)
    		return -ENOMEM;
    
    	return 0;
    }
    
    static void __net_exit tcp_net_metrics_exit(struct net *net)
    {
    
    	unsigned int i;
    
    	for (i = 0; i < (1U << net->ipv4.tcp_metrics_hash_log) ; i++) {
    		struct tcp_metrics_block *tm, *next;
    
    		tm = rcu_dereference_protected(net->ipv4.tcp_metrics_hash[i].chain, 1);
    		while (tm) {
    			next = rcu_dereference_protected(tm->tcpm_next, 1);
    			kfree(tm);
    			tm = next;
    		}
    	}
    
    	if (is_vmalloc_addr(net->ipv4.tcp_metrics_hash))
    		vfree(net->ipv4.tcp_metrics_hash);
    	else
    		kfree(net->ipv4.tcp_metrics_hash);
    
    }
    
    static __net_initdata struct pernet_operations tcp_net_metrics_ops = {
    	.init	=	tcp_net_metrics_init,
    	.exit	=	tcp_net_metrics_exit,
    };
    
    void __init tcp_metrics_init(void)
    {
    
    	int ret;
    
    	ret = register_pernet_subsys(&tcp_net_metrics_ops);
    	if (ret < 0)
    		goto cleanup;
    	ret = genl_register_family_with_ops(&tcp_metrics_nl_family,
    					    tcp_metrics_nl_ops,
    					    ARRAY_SIZE(tcp_metrics_nl_ops));
    	if (ret < 0)
    		goto cleanup_subsys;
    	return;
    
    cleanup_subsys:
    	unregister_pernet_subsys(&tcp_net_metrics_ops);
    
    cleanup:
    	return;