sysctl_net_core.c 5.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10
/* -*- linux-c -*-
 * sysctl_net_core.c: sysctl interface to net core subsystem.
 *
 * Begun April 1, 1996, Mike Shaver.
 * Added /proc/sys/net/core directory entry (empty =) ). [MS]
 */

#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/module.h>
11
#include <linux/socket.h>
12
#include <linux/netdevice.h>
13
#include <linux/ratelimit.h>
T
Tom Herbert 已提交
14
#include <linux/vmalloc.h>
15
#include <linux/init.h>
16
#include <linux/slab.h>
17

18
#include <net/ip.h>
19
#include <net/sock.h>
20
#include <net/net_ratelimit.h>
L
Linus Torvalds 已提交
21

T
Tom Herbert 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
#ifdef CONFIG_RPS
static int rps_sock_flow_sysctl(ctl_table *table, int write,
				void __user *buffer, size_t *lenp, loff_t *ppos)
{
	unsigned int orig_size, size;
	int ret, i;
	ctl_table tmp = {
		.data = &size,
		.maxlen = sizeof(size),
		.mode = table->mode
	};
	struct rps_sock_flow_table *orig_sock_table, *sock_table;
	static DEFINE_MUTEX(sock_flow_mutex);

	mutex_lock(&sock_flow_mutex);

E
Eric Dumazet 已提交
38 39
	orig_sock_table = rcu_dereference_protected(rps_sock_flow_table,
					lockdep_is_held(&sock_flow_mutex));
T
Tom Herbert 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	size = orig_size = orig_sock_table ? orig_sock_table->mask + 1 : 0;

	ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);

	if (write) {
		if (size) {
			if (size > 1<<30) {
				/* Enforce limit to prevent overflow */
				mutex_unlock(&sock_flow_mutex);
				return -EINVAL;
			}
			size = roundup_pow_of_two(size);
			if (size != orig_size) {
				sock_table =
				    vmalloc(RPS_SOCK_FLOW_TABLE_SIZE(size));
				if (!sock_table) {
					mutex_unlock(&sock_flow_mutex);
					return -ENOMEM;
				}

				sock_table->mask = size - 1;
			} else
				sock_table = orig_sock_table;

			for (i = 0; i < size; i++)
				sock_table->ents[i] = RPS_NO_CPU;
		} else
			sock_table = NULL;

		if (sock_table != orig_sock_table) {
			rcu_assign_pointer(rps_sock_flow_table, sock_table);
71
			if (sock_table)
72
				static_key_slow_inc(&rps_needed);
73
			if (orig_sock_table) {
74
				static_key_slow_dec(&rps_needed);
75 76 77
				synchronize_rcu();
				vfree(orig_sock_table);
			}
T
Tom Herbert 已提交
78 79 80 81 82 83 84 85 86
		}
	}

	mutex_unlock(&sock_flow_mutex);

	return ret;
}
#endif /* CONFIG_RPS */

87
static struct ctl_table net_core_table[] = {
L
Linus Torvalds 已提交
88 89 90 91 92 93
#ifdef CONFIG_NET
	{
		.procname	= "wmem_max",
		.data		= &sysctl_wmem_max,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
94
		.proc_handler	= proc_dointvec
L
Linus Torvalds 已提交
95 96 97 98 99 100
	},
	{
		.procname	= "rmem_max",
		.data		= &sysctl_rmem_max,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
101
		.proc_handler	= proc_dointvec
L
Linus Torvalds 已提交
102 103 104 105 106 107
	},
	{
		.procname	= "wmem_default",
		.data		= &sysctl_wmem_default,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
108
		.proc_handler	= proc_dointvec
L
Linus Torvalds 已提交
109 110 111 112 113 114
	},
	{
		.procname	= "rmem_default",
		.data		= &sysctl_rmem_default,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
115
		.proc_handler	= proc_dointvec
L
Linus Torvalds 已提交
116 117 118 119 120 121
	},
	{
		.procname	= "dev_weight",
		.data		= &weight_p,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
122
		.proc_handler	= proc_dointvec
L
Linus Torvalds 已提交
123 124 125 126 127 128
	},
	{
		.procname	= "netdev_max_backlog",
		.data		= &netdev_max_backlog,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
129
		.proc_handler	= proc_dointvec
L
Linus Torvalds 已提交
130
	},
131 132 133 134 135 136 137 138 139
#ifdef CONFIG_BPF_JIT
	{
		.procname	= "bpf_jit_enable",
		.data		= &bpf_jit_enable,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= proc_dointvec
	},
#endif
E
Eric Dumazet 已提交
140 141 142 143 144 145 146
	{
		.procname	= "netdev_tstamp_prequeue",
		.data		= &netdev_tstamp_prequeue,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= proc_dointvec
	},
L
Linus Torvalds 已提交
147 148
	{
		.procname	= "message_cost",
D
Dave Young 已提交
149
		.data		= &net_ratelimit_state.interval,
L
Linus Torvalds 已提交
150 151
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
152
		.proc_handler	= proc_dointvec_jiffies,
L
Linus Torvalds 已提交
153 154 155
	},
	{
		.procname	= "message_burst",
D
Dave Young 已提交
156
		.data		= &net_ratelimit_state.burst,
L
Linus Torvalds 已提交
157 158
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
159
		.proc_handler	= proc_dointvec,
L
Linus Torvalds 已提交
160 161 162 163 164 165
	},
	{
		.procname	= "optmem_max",
		.data		= &sysctl_optmem_max,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
166
		.proc_handler	= proc_dointvec
L
Linus Torvalds 已提交
167
	},
T
Tom Herbert 已提交
168 169 170 171 172 173 174 175
#ifdef CONFIG_RPS
	{
		.procname	= "rps_sock_flow_entries",
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= rps_sock_flow_sysctl
	},
#endif
L
Linus Torvalds 已提交
176
#endif /* CONFIG_NET */
177 178 179 180 181
	{
		.procname	= "netdev_budget",
		.data		= &netdev_budget,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
182
		.proc_handler	= proc_dointvec
183
	},
184 185 186 187 188
	{
		.procname	= "warnings",
		.data		= &net_msg_warn,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
189
		.proc_handler	= proc_dointvec
190
	},
191
	{ }
L
Linus Torvalds 已提交
192
};
193

194 195 196 197 198 199
static struct ctl_table netns_core_table[] = {
	{
		.procname	= "somaxconn",
		.data		= &init_net.core.sysctl_somaxconn,
		.maxlen		= sizeof(int),
		.mode		= 0644,
A
Alexey Dobriyan 已提交
200
		.proc_handler	= proc_dointvec
201
	},
202
	{ }
203 204
};

A
Alexey Dobriyan 已提交
205
__net_initdata struct ctl_path net_core_path[] = {
206 207
	{ .procname = "net", },
	{ .procname = "core", },
208 209 210
	{ },
};

211
static __net_init int sysctl_core_net_init(struct net *net)
212
{
213
	struct ctl_table *tbl;
214

215
	net->core.sysctl_somaxconn = SOMAXCONN;
216

217
	tbl = netns_core_table;
O
Octavian Purdila 已提交
218
	if (!net_eq(net, &init_net)) {
219
		tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
220 221 222
		if (tbl == NULL)
			goto err_dup;

223
		tbl[0].data = &net->core.sysctl_somaxconn;
224 225
	}

226
	net->core.sysctl_hdr = register_net_sysctl_table(net,
227
			net_core_path, tbl);
228
	if (net->core.sysctl_hdr == NULL)
229
		goto err_reg;
230

231 232 233
	return 0;

err_reg:
234
	if (tbl != netns_core_table)
235 236 237 238 239 240 241 242 243
		kfree(tbl);
err_dup:
	return -ENOMEM;
}

static __net_exit void sysctl_core_net_exit(struct net *net)
{
	struct ctl_table *tbl;

244 245
	tbl = net->core.sysctl_hdr->ctl_table_arg;
	unregister_net_sysctl_table(net->core.sysctl_hdr);
246
	BUG_ON(tbl == netns_core_table);
247 248 249 250 251 252 253 254 255 256
	kfree(tbl);
}

static __net_initdata struct pernet_operations sysctl_core_ops = {
	.init = sysctl_core_net_init,
	.exit = sysctl_core_net_exit,
};

static __init int sysctl_core_init(void)
{
A
Alexey Dobriyan 已提交
257 258
	static struct ctl_table empty[1];

259
	kmemleak_not_leak(register_sysctl_paths(net_core_path, empty));
260
	register_net_sysctl_rotable(net_core_path, net_core_table);
261
	return register_pernet_subsys(&sysctl_core_ops);
262 263
}

A
Alexey Dobriyan 已提交
264
fs_initcall(sysctl_core_init);