xref: /kernel/linux/linux-6.6/net/mptcp/ctrl.c (revision 62306a36)
1// SPDX-License-Identifier: GPL-2.0
2/* Multipath TCP
3 *
4 * Copyright (c) 2019, Tessares SA.
5 */
6
7#ifdef CONFIG_SYSCTL
8#include <linux/sysctl.h>
9#endif
10
11#include <net/net_namespace.h>
12#include <net/netns/generic.h>
13
14#include "protocol.h"
15
16#define MPTCP_SYSCTL_PATH "net/mptcp"
17
18static int mptcp_pernet_id;
19
20#ifdef CONFIG_SYSCTL
21static int mptcp_pm_type_max = __MPTCP_PM_TYPE_MAX;
22#endif
23
24struct mptcp_pernet {
25#ifdef CONFIG_SYSCTL
26	struct ctl_table_header *ctl_table_hdr;
27#endif
28
29	unsigned int add_addr_timeout;
30	unsigned int stale_loss_cnt;
31	u8 mptcp_enabled;
32	u8 checksum_enabled;
33	u8 allow_join_initial_addr_port;
34	u8 pm_type;
35	char scheduler[MPTCP_SCHED_NAME_MAX];
36};
37
38static struct mptcp_pernet *mptcp_get_pernet(const struct net *net)
39{
40	return net_generic(net, mptcp_pernet_id);
41}
42
43int mptcp_is_enabled(const struct net *net)
44{
45	return mptcp_get_pernet(net)->mptcp_enabled;
46}
47
48unsigned int mptcp_get_add_addr_timeout(const struct net *net)
49{
50	return mptcp_get_pernet(net)->add_addr_timeout;
51}
52
53int mptcp_is_checksum_enabled(const struct net *net)
54{
55	return mptcp_get_pernet(net)->checksum_enabled;
56}
57
58int mptcp_allow_join_id0(const struct net *net)
59{
60	return mptcp_get_pernet(net)->allow_join_initial_addr_port;
61}
62
63unsigned int mptcp_stale_loss_cnt(const struct net *net)
64{
65	return mptcp_get_pernet(net)->stale_loss_cnt;
66}
67
68int mptcp_get_pm_type(const struct net *net)
69{
70	return mptcp_get_pernet(net)->pm_type;
71}
72
73const char *mptcp_get_scheduler(const struct net *net)
74{
75	return mptcp_get_pernet(net)->scheduler;
76}
77
78static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet)
79{
80	pernet->mptcp_enabled = 1;
81	pernet->add_addr_timeout = TCP_RTO_MAX;
82	pernet->checksum_enabled = 0;
83	pernet->allow_join_initial_addr_port = 1;
84	pernet->stale_loss_cnt = 4;
85	pernet->pm_type = MPTCP_PM_TYPE_KERNEL;
86	strcpy(pernet->scheduler, "default");
87}
88
89#ifdef CONFIG_SYSCTL
90static struct ctl_table mptcp_sysctl_table[] = {
91	{
92		.procname = "enabled",
93		.maxlen = sizeof(u8),
94		.mode = 0644,
95		/* users with CAP_NET_ADMIN or root (not and) can change this
96		 * value, same as other sysctl or the 'net' tree.
97		 */
98		.proc_handler = proc_dou8vec_minmax,
99		.extra1       = SYSCTL_ZERO,
100		.extra2       = SYSCTL_ONE
101	},
102	{
103		.procname = "add_addr_timeout",
104		.maxlen = sizeof(unsigned int),
105		.mode = 0644,
106		.proc_handler = proc_dointvec_jiffies,
107	},
108	{
109		.procname = "checksum_enabled",
110		.maxlen = sizeof(u8),
111		.mode = 0644,
112		.proc_handler = proc_dou8vec_minmax,
113		.extra1       = SYSCTL_ZERO,
114		.extra2       = SYSCTL_ONE
115	},
116	{
117		.procname = "allow_join_initial_addr_port",
118		.maxlen = sizeof(u8),
119		.mode = 0644,
120		.proc_handler = proc_dou8vec_minmax,
121		.extra1       = SYSCTL_ZERO,
122		.extra2       = SYSCTL_ONE
123	},
124	{
125		.procname = "stale_loss_cnt",
126		.maxlen = sizeof(unsigned int),
127		.mode = 0644,
128		.proc_handler = proc_douintvec_minmax,
129	},
130	{
131		.procname = "pm_type",
132		.maxlen = sizeof(u8),
133		.mode = 0644,
134		.proc_handler = proc_dou8vec_minmax,
135		.extra1       = SYSCTL_ZERO,
136		.extra2       = &mptcp_pm_type_max
137	},
138	{
139		.procname = "scheduler",
140		.maxlen	= MPTCP_SCHED_NAME_MAX,
141		.mode = 0644,
142		.proc_handler = proc_dostring,
143	},
144	{}
145};
146
147static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
148{
149	struct ctl_table_header *hdr;
150	struct ctl_table *table;
151
152	table = mptcp_sysctl_table;
153	if (!net_eq(net, &init_net)) {
154		table = kmemdup(table, sizeof(mptcp_sysctl_table), GFP_KERNEL);
155		if (!table)
156			goto err_alloc;
157	}
158
159	table[0].data = &pernet->mptcp_enabled;
160	table[1].data = &pernet->add_addr_timeout;
161	table[2].data = &pernet->checksum_enabled;
162	table[3].data = &pernet->allow_join_initial_addr_port;
163	table[4].data = &pernet->stale_loss_cnt;
164	table[5].data = &pernet->pm_type;
165	table[6].data = &pernet->scheduler;
166
167	hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table,
168				     ARRAY_SIZE(mptcp_sysctl_table));
169	if (!hdr)
170		goto err_reg;
171
172	pernet->ctl_table_hdr = hdr;
173
174	return 0;
175
176err_reg:
177	if (!net_eq(net, &init_net))
178		kfree(table);
179err_alloc:
180	return -ENOMEM;
181}
182
183static void mptcp_pernet_del_table(struct mptcp_pernet *pernet)
184{
185	struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg;
186
187	unregister_net_sysctl_table(pernet->ctl_table_hdr);
188
189	kfree(table);
190}
191
192#else
193
194static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
195{
196	return 0;
197}
198
199static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {}
200
201#endif /* CONFIG_SYSCTL */
202
203static int __net_init mptcp_net_init(struct net *net)
204{
205	struct mptcp_pernet *pernet = mptcp_get_pernet(net);
206
207	mptcp_pernet_set_defaults(pernet);
208
209	return mptcp_pernet_new_table(net, pernet);
210}
211
212/* Note: the callback will only be called per extra netns */
213static void __net_exit mptcp_net_exit(struct net *net)
214{
215	struct mptcp_pernet *pernet = mptcp_get_pernet(net);
216
217	mptcp_pernet_del_table(pernet);
218}
219
220static struct pernet_operations mptcp_pernet_ops = {
221	.init = mptcp_net_init,
222	.exit = mptcp_net_exit,
223	.id = &mptcp_pernet_id,
224	.size = sizeof(struct mptcp_pernet),
225};
226
227void __init mptcp_init(void)
228{
229	mptcp_join_cookie_init();
230	mptcp_proto_init();
231
232	if (register_pernet_subsys(&mptcp_pernet_ops) < 0)
233		panic("Failed to register MPTCP pernet subsystem.\n");
234}
235
236#if IS_ENABLED(CONFIG_MPTCP_IPV6)
237int __init mptcpv6_init(void)
238{
239	int err;
240
241	err = mptcp_proto_v6_init();
242
243	return err;
244}
245#endif
246