xref: /openbmc/linux/net/mptcp/ctrl.c (revision d32fd6bb9f2bc8178cdd65ebec1ad670a8bfa241)
1784325e9SMatthieu Baerts // SPDX-License-Identifier: GPL-2.0
2784325e9SMatthieu Baerts /* Multipath TCP
3784325e9SMatthieu Baerts  *
4784325e9SMatthieu Baerts  * Copyright (c) 2019, Tessares SA.
5784325e9SMatthieu Baerts  */
6784325e9SMatthieu Baerts 
7804c72eeSMatthieu Baerts #ifdef CONFIG_SYSCTL
8784325e9SMatthieu Baerts #include <linux/sysctl.h>
9804c72eeSMatthieu Baerts #endif
10784325e9SMatthieu Baerts 
11784325e9SMatthieu Baerts #include <net/net_namespace.h>
12784325e9SMatthieu Baerts #include <net/netns/generic.h>
13784325e9SMatthieu Baerts 
14784325e9SMatthieu Baerts #include "protocol.h"
15784325e9SMatthieu Baerts 
16784325e9SMatthieu Baerts #define MPTCP_SYSCTL_PATH "net/mptcp"
17784325e9SMatthieu Baerts 
18784325e9SMatthieu Baerts static int mptcp_pernet_id;
196bb63cccSMat Martineau 
206bb63cccSMat Martineau #ifdef CONFIG_SYSCTL
216bb63cccSMat Martineau static int mptcp_pm_type_max = __MPTCP_PM_TYPE_MAX;
226bb63cccSMat Martineau #endif
236bb63cccSMat Martineau 
24784325e9SMatthieu Baerts struct mptcp_pernet {
25804c72eeSMatthieu Baerts #ifdef CONFIG_SYSCTL
26784325e9SMatthieu Baerts 	struct ctl_table_header *ctl_table_hdr;
27804c72eeSMatthieu Baerts #endif
28784325e9SMatthieu Baerts 
2993f323b9SGeliang Tang 	unsigned int add_addr_timeout;
30ff5a0b42SPaolo Abeni 	unsigned int stale_loss_cnt;
316da14d74SPaolo Abeni 	u8 mptcp_enabled;
32fc3c82eeSGeliang Tang 	u8 checksum_enabled;
33d2f77960SGeliang Tang 	u8 allow_join_initial_addr_port;
346bb63cccSMat Martineau 	u8 pm_type;
35e3b2870bSGeliang Tang 	char scheduler[MPTCP_SCHED_NAME_MAX];
36784325e9SMatthieu Baerts };
37784325e9SMatthieu Baerts 
mptcp_get_pernet(const struct net * net)386da14d74SPaolo Abeni static struct mptcp_pernet *mptcp_get_pernet(const struct net *net)
39784325e9SMatthieu Baerts {
40784325e9SMatthieu Baerts 	return net_generic(net, mptcp_pernet_id);
41784325e9SMatthieu Baerts }
42784325e9SMatthieu Baerts 
mptcp_is_enabled(const struct net * net)436da14d74SPaolo Abeni int mptcp_is_enabled(const struct net *net)
44784325e9SMatthieu Baerts {
45784325e9SMatthieu Baerts 	return mptcp_get_pernet(net)->mptcp_enabled;
46784325e9SMatthieu Baerts }
47784325e9SMatthieu Baerts 
mptcp_get_add_addr_timeout(const struct net * net)486da14d74SPaolo Abeni unsigned int mptcp_get_add_addr_timeout(const struct net *net)
4993f323b9SGeliang Tang {
5093f323b9SGeliang Tang 	return mptcp_get_pernet(net)->add_addr_timeout;
5193f323b9SGeliang Tang }
5293f323b9SGeliang Tang 
mptcp_is_checksum_enabled(const struct net * net)536da14d74SPaolo Abeni int mptcp_is_checksum_enabled(const struct net *net)
54fc3c82eeSGeliang Tang {
55fc3c82eeSGeliang Tang 	return mptcp_get_pernet(net)->checksum_enabled;
56fc3c82eeSGeliang Tang }
57fc3c82eeSGeliang Tang 
mptcp_allow_join_id0(const struct net * net)586da14d74SPaolo Abeni int mptcp_allow_join_id0(const struct net *net)
59d2f77960SGeliang Tang {
60d2f77960SGeliang Tang 	return mptcp_get_pernet(net)->allow_join_initial_addr_port;
61d2f77960SGeliang Tang }
62d2f77960SGeliang Tang 
mptcp_stale_loss_cnt(const struct net * net)63ff5a0b42SPaolo Abeni unsigned int mptcp_stale_loss_cnt(const struct net *net)
64ff5a0b42SPaolo Abeni {
65ff5a0b42SPaolo Abeni 	return mptcp_get_pernet(net)->stale_loss_cnt;
66ff5a0b42SPaolo Abeni }
67ff5a0b42SPaolo Abeni 
mptcp_get_pm_type(const struct net * net)686bb63cccSMat Martineau int mptcp_get_pm_type(const struct net *net)
696bb63cccSMat Martineau {
706bb63cccSMat Martineau 	return mptcp_get_pernet(net)->pm_type;
716bb63cccSMat Martineau }
726bb63cccSMat Martineau 
mptcp_get_scheduler(const struct net * net)73e3b2870bSGeliang Tang const char *mptcp_get_scheduler(const struct net *net)
74e3b2870bSGeliang Tang {
75e3b2870bSGeliang Tang 	return mptcp_get_pernet(net)->scheduler;
76e3b2870bSGeliang Tang }
77e3b2870bSGeliang Tang 
mptcp_pernet_set_defaults(struct mptcp_pernet * pernet)78804c72eeSMatthieu Baerts static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet)
79804c72eeSMatthieu Baerts {
80804c72eeSMatthieu Baerts 	pernet->mptcp_enabled = 1;
81804c72eeSMatthieu Baerts 	pernet->add_addr_timeout = TCP_RTO_MAX;
82fc3c82eeSGeliang Tang 	pernet->checksum_enabled = 0;
83d2f77960SGeliang Tang 	pernet->allow_join_initial_addr_port = 1;
84ff5a0b42SPaolo Abeni 	pernet->stale_loss_cnt = 4;
856bb63cccSMat Martineau 	pernet->pm_type = MPTCP_PM_TYPE_KERNEL;
86e3b2870bSGeliang Tang 	strcpy(pernet->scheduler, "default");
87804c72eeSMatthieu Baerts }
88804c72eeSMatthieu Baerts 
89804c72eeSMatthieu Baerts #ifdef CONFIG_SYSCTL
mptcp_set_scheduler(char * scheduler,const char * name)90*c0e394fdSMatthieu Baerts (NGI0) static int mptcp_set_scheduler(char *scheduler, const char *name)
91daad878aSGregory Detal {
92daad878aSGregory Detal 	struct mptcp_sched_ops *sched;
93daad878aSGregory Detal 	int ret = 0;
94daad878aSGregory Detal 
95daad878aSGregory Detal 	rcu_read_lock();
96daad878aSGregory Detal 	sched = mptcp_sched_find(name);
97daad878aSGregory Detal 	if (sched)
98*c0e394fdSMatthieu Baerts (NGI0) 		strscpy(scheduler, name, MPTCP_SCHED_NAME_MAX);
99daad878aSGregory Detal 	else
100daad878aSGregory Detal 		ret = -ENOENT;
101daad878aSGregory Detal 	rcu_read_unlock();
102daad878aSGregory Detal 
103daad878aSGregory Detal 	return ret;
104daad878aSGregory Detal }
105daad878aSGregory Detal 
proc_scheduler(struct ctl_table * ctl,int write,void * buffer,size_t * lenp,loff_t * ppos)106daad878aSGregory Detal static int proc_scheduler(struct ctl_table *ctl, int write,
107daad878aSGregory Detal 			  void *buffer, size_t *lenp, loff_t *ppos)
108daad878aSGregory Detal {
109*c0e394fdSMatthieu Baerts (NGI0) 	char (*scheduler)[MPTCP_SCHED_NAME_MAX] = ctl->data;
110daad878aSGregory Detal 	char val[MPTCP_SCHED_NAME_MAX];
111daad878aSGregory Detal 	struct ctl_table tbl = {
112daad878aSGregory Detal 		.data = val,
113daad878aSGregory Detal 		.maxlen = MPTCP_SCHED_NAME_MAX,
114daad878aSGregory Detal 	};
115daad878aSGregory Detal 	int ret;
116daad878aSGregory Detal 
117*c0e394fdSMatthieu Baerts (NGI0) 	strscpy(val, *scheduler, MPTCP_SCHED_NAME_MAX);
118daad878aSGregory Detal 
119daad878aSGregory Detal 	ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
120daad878aSGregory Detal 	if (write && ret == 0)
121*c0e394fdSMatthieu Baerts (NGI0) 		ret = mptcp_set_scheduler(*scheduler, val);
122daad878aSGregory Detal 
123daad878aSGregory Detal 	return ret;
124daad878aSGregory Detal }
125daad878aSGregory Detal 
126784325e9SMatthieu Baerts static struct ctl_table mptcp_sysctl_table[] = {
127784325e9SMatthieu Baerts 	{
128784325e9SMatthieu Baerts 		.procname = "enabled",
129744ee140SMatthieu Baerts 		.maxlen = sizeof(u8),
130784325e9SMatthieu Baerts 		.mode = 0644,
131784325e9SMatthieu Baerts 		/* users with CAP_NET_ADMIN or root (not and) can change this
132784325e9SMatthieu Baerts 		 * value, same as other sysctl or the 'net' tree.
133784325e9SMatthieu Baerts 		 */
134744ee140SMatthieu Baerts 		.proc_handler = proc_dou8vec_minmax,
135744ee140SMatthieu Baerts 		.extra1       = SYSCTL_ZERO,
136744ee140SMatthieu Baerts 		.extra2       = SYSCTL_ONE
137784325e9SMatthieu Baerts 	},
13893f323b9SGeliang Tang 	{
13993f323b9SGeliang Tang 		.procname = "add_addr_timeout",
14093f323b9SGeliang Tang 		.maxlen = sizeof(unsigned int),
14193f323b9SGeliang Tang 		.mode = 0644,
14293f323b9SGeliang Tang 		.proc_handler = proc_dointvec_jiffies,
14393f323b9SGeliang Tang 	},
144fc3c82eeSGeliang Tang 	{
145fc3c82eeSGeliang Tang 		.procname = "checksum_enabled",
146fc3c82eeSGeliang Tang 		.maxlen = sizeof(u8),
147fc3c82eeSGeliang Tang 		.mode = 0644,
148fc3c82eeSGeliang Tang 		.proc_handler = proc_dou8vec_minmax,
149fc3c82eeSGeliang Tang 		.extra1       = SYSCTL_ZERO,
150fc3c82eeSGeliang Tang 		.extra2       = SYSCTL_ONE
151fc3c82eeSGeliang Tang 	},
152d2f77960SGeliang Tang 	{
153d2f77960SGeliang Tang 		.procname = "allow_join_initial_addr_port",
154d2f77960SGeliang Tang 		.maxlen = sizeof(u8),
155d2f77960SGeliang Tang 		.mode = 0644,
156d2f77960SGeliang Tang 		.proc_handler = proc_dou8vec_minmax,
157d2f77960SGeliang Tang 		.extra1       = SYSCTL_ZERO,
158d2f77960SGeliang Tang 		.extra2       = SYSCTL_ONE
159d2f77960SGeliang Tang 	},
160ff5a0b42SPaolo Abeni 	{
161ff5a0b42SPaolo Abeni 		.procname = "stale_loss_cnt",
162ff5a0b42SPaolo Abeni 		.maxlen = sizeof(unsigned int),
163ff5a0b42SPaolo Abeni 		.mode = 0644,
164ff5a0b42SPaolo Abeni 		.proc_handler = proc_douintvec_minmax,
165ff5a0b42SPaolo Abeni 	},
1666bb63cccSMat Martineau 	{
1676bb63cccSMat Martineau 		.procname = "pm_type",
1686bb63cccSMat Martineau 		.maxlen = sizeof(u8),
1696bb63cccSMat Martineau 		.mode = 0644,
1706bb63cccSMat Martineau 		.proc_handler = proc_dou8vec_minmax,
1716bb63cccSMat Martineau 		.extra1       = SYSCTL_ZERO,
1726bb63cccSMat Martineau 		.extra2       = &mptcp_pm_type_max
1736bb63cccSMat Martineau 	},
174e3b2870bSGeliang Tang 	{
175e3b2870bSGeliang Tang 		.procname = "scheduler",
176e3b2870bSGeliang Tang 		.maxlen	= MPTCP_SCHED_NAME_MAX,
177e3b2870bSGeliang Tang 		.mode = 0644,
178daad878aSGregory Detal 		.proc_handler = proc_scheduler,
179e3b2870bSGeliang Tang 	},
180784325e9SMatthieu Baerts 	{}
181784325e9SMatthieu Baerts };
182784325e9SMatthieu Baerts 
mptcp_pernet_new_table(struct net * net,struct mptcp_pernet * pernet)183784325e9SMatthieu Baerts static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
184784325e9SMatthieu Baerts {
185784325e9SMatthieu Baerts 	struct ctl_table_header *hdr;
186784325e9SMatthieu Baerts 	struct ctl_table *table;
187784325e9SMatthieu Baerts 
188784325e9SMatthieu Baerts 	table = mptcp_sysctl_table;
189784325e9SMatthieu Baerts 	if (!net_eq(net, &init_net)) {
190784325e9SMatthieu Baerts 		table = kmemdup(table, sizeof(mptcp_sysctl_table), GFP_KERNEL);
191784325e9SMatthieu Baerts 		if (!table)
192784325e9SMatthieu Baerts 			goto err_alloc;
193784325e9SMatthieu Baerts 	}
194784325e9SMatthieu Baerts 
195784325e9SMatthieu Baerts 	table[0].data = &pernet->mptcp_enabled;
19693f323b9SGeliang Tang 	table[1].data = &pernet->add_addr_timeout;
197fc3c82eeSGeliang Tang 	table[2].data = &pernet->checksum_enabled;
198d2f77960SGeliang Tang 	table[3].data = &pernet->allow_join_initial_addr_port;
199ff5a0b42SPaolo Abeni 	table[4].data = &pernet->stale_loss_cnt;
2006bb63cccSMat Martineau 	table[5].data = &pernet->pm_type;
201e3b2870bSGeliang Tang 	table[6].data = &pernet->scheduler;
202784325e9SMatthieu Baerts 
203c899710fSJoel Granados 	hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table,
204c899710fSJoel Granados 				     ARRAY_SIZE(mptcp_sysctl_table));
205784325e9SMatthieu Baerts 	if (!hdr)
206784325e9SMatthieu Baerts 		goto err_reg;
207784325e9SMatthieu Baerts 
208784325e9SMatthieu Baerts 	pernet->ctl_table_hdr = hdr;
209784325e9SMatthieu Baerts 
210784325e9SMatthieu Baerts 	return 0;
211784325e9SMatthieu Baerts 
212784325e9SMatthieu Baerts err_reg:
213784325e9SMatthieu Baerts 	if (!net_eq(net, &init_net))
214784325e9SMatthieu Baerts 		kfree(table);
215784325e9SMatthieu Baerts err_alloc:
216784325e9SMatthieu Baerts 	return -ENOMEM;
217784325e9SMatthieu Baerts }
218784325e9SMatthieu Baerts 
mptcp_pernet_del_table(struct mptcp_pernet * pernet)219784325e9SMatthieu Baerts static void mptcp_pernet_del_table(struct mptcp_pernet *pernet)
220784325e9SMatthieu Baerts {
221784325e9SMatthieu Baerts 	struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg;
222784325e9SMatthieu Baerts 
223784325e9SMatthieu Baerts 	unregister_net_sysctl_table(pernet->ctl_table_hdr);
224784325e9SMatthieu Baerts 
225784325e9SMatthieu Baerts 	kfree(table);
226784325e9SMatthieu Baerts }
227784325e9SMatthieu Baerts 
228804c72eeSMatthieu Baerts #else
229804c72eeSMatthieu Baerts 
mptcp_pernet_new_table(struct net * net,struct mptcp_pernet * pernet)230804c72eeSMatthieu Baerts static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
231804c72eeSMatthieu Baerts {
232804c72eeSMatthieu Baerts 	return 0;
233804c72eeSMatthieu Baerts }
234804c72eeSMatthieu Baerts 
mptcp_pernet_del_table(struct mptcp_pernet * pernet)235804c72eeSMatthieu Baerts static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {}
236804c72eeSMatthieu Baerts 
237804c72eeSMatthieu Baerts #endif /* CONFIG_SYSCTL */
238804c72eeSMatthieu Baerts 
mptcp_net_init(struct net * net)239784325e9SMatthieu Baerts static int __net_init mptcp_net_init(struct net *net)
240784325e9SMatthieu Baerts {
241784325e9SMatthieu Baerts 	struct mptcp_pernet *pernet = mptcp_get_pernet(net);
242784325e9SMatthieu Baerts 
243784325e9SMatthieu Baerts 	mptcp_pernet_set_defaults(pernet);
244784325e9SMatthieu Baerts 
245784325e9SMatthieu Baerts 	return mptcp_pernet_new_table(net, pernet);
246784325e9SMatthieu Baerts }
247784325e9SMatthieu Baerts 
248784325e9SMatthieu Baerts /* Note: the callback will only be called per extra netns */
mptcp_net_exit(struct net * net)249784325e9SMatthieu Baerts static void __net_exit mptcp_net_exit(struct net *net)
250784325e9SMatthieu Baerts {
251784325e9SMatthieu Baerts 	struct mptcp_pernet *pernet = mptcp_get_pernet(net);
252784325e9SMatthieu Baerts 
253784325e9SMatthieu Baerts 	mptcp_pernet_del_table(pernet);
254784325e9SMatthieu Baerts }
255784325e9SMatthieu Baerts 
256784325e9SMatthieu Baerts static struct pernet_operations mptcp_pernet_ops = {
257784325e9SMatthieu Baerts 	.init = mptcp_net_init,
258784325e9SMatthieu Baerts 	.exit = mptcp_net_exit,
259784325e9SMatthieu Baerts 	.id = &mptcp_pernet_id,
260784325e9SMatthieu Baerts 	.size = sizeof(struct mptcp_pernet),
261784325e9SMatthieu Baerts };
262784325e9SMatthieu Baerts 
mptcp_init(void)263784325e9SMatthieu Baerts void __init mptcp_init(void)
264784325e9SMatthieu Baerts {
2659466a1ccSFlorian Westphal 	mptcp_join_cookie_init();
266784325e9SMatthieu Baerts 	mptcp_proto_init();
267784325e9SMatthieu Baerts 
268784325e9SMatthieu Baerts 	if (register_pernet_subsys(&mptcp_pernet_ops) < 0)
269784325e9SMatthieu Baerts 		panic("Failed to register MPTCP pernet subsystem.\n");
270784325e9SMatthieu Baerts }
271784325e9SMatthieu Baerts 
272784325e9SMatthieu Baerts #if IS_ENABLED(CONFIG_MPTCP_IPV6)
mptcpv6_init(void)273784325e9SMatthieu Baerts int __init mptcpv6_init(void)
274784325e9SMatthieu Baerts {
275784325e9SMatthieu Baerts 	int err;
276784325e9SMatthieu Baerts 
277784325e9SMatthieu Baerts 	err = mptcp_proto_v6_init();
278784325e9SMatthieu Baerts 
279784325e9SMatthieu Baerts 	return err;
280784325e9SMatthieu Baerts }
281784325e9SMatthieu Baerts #endif
282