Branch data Line data Source code
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 : : #include "mib.h"
16 : :
17 : : #define MPTCP_SYSCTL_PATH "net/mptcp"
18 : :
19 : : static int mptcp_pernet_id;
20 : :
21 : : #ifdef CONFIG_SYSCTL
22 : : static int mptcp_pm_type_max = __MPTCP_PM_TYPE_MAX;
23 : : #endif
24 : :
25 : : struct mptcp_pernet {
26 : : #ifdef CONFIG_SYSCTL
27 : : struct ctl_table_header *ctl_table_hdr;
28 : : #endif
29 : :
30 : : unsigned int add_addr_timeout;
31 : : unsigned int blackhole_timeout;
32 : : unsigned int close_timeout;
33 : : unsigned int stale_loss_cnt;
34 : : atomic_t active_disable_times;
35 : : u8 syn_retrans_before_tcp_fallback;
36 : : unsigned long active_disable_stamp;
37 : : u8 mptcp_enabled;
38 : : u8 checksum_enabled;
39 : : u8 allow_join_initial_addr_port;
40 : : u8 pm_type;
41 : : char scheduler[MPTCP_SCHED_NAME_MAX];
42 : : char path_manager[MPTCP_PM_NAME_MAX];
43 : : };
44 : :
45 : 15536 : static struct mptcp_pernet *mptcp_get_pernet(const struct net *net)
46 : : {
47 : 16109 : return net_generic(net, mptcp_pernet_id);
48 : : }
49 : :
50 : 2546 : int mptcp_is_enabled(const struct net *net)
51 : : {
52 : 2546 : return mptcp_get_pernet(net)->mptcp_enabled;
53 : : }
54 : :
55 : 392 : unsigned int mptcp_get_add_addr_timeout(const struct net *net)
56 : : {
57 : 392 : return mptcp_get_pernet(net)->add_addr_timeout;
58 : : }
59 : :
60 : 6913 : int mptcp_is_checksum_enabled(const struct net *net)
61 : : {
62 : 6913 : return mptcp_get_pernet(net)->checksum_enabled;
63 : : }
64 : :
65 : 4868 : int mptcp_allow_join_id0(const struct net *net)
66 : : {
67 : 4868 : return mptcp_get_pernet(net)->allow_join_initial_addr_port;
68 : : }
69 : :
70 : 1777 : unsigned int mptcp_stale_loss_cnt(const struct net *net)
71 : : {
72 : 1777 : return mptcp_get_pernet(net)->stale_loss_cnt;
73 : : }
74 : :
75 : 4900 : unsigned int mptcp_close_timeout(const struct sock *sk)
76 : : {
77 [ + + ]: 4900 : if (sock_flag(sk, SOCK_DEAD))
78 : : return TCP_TIMEWAIT_LEN;
79 : 112 : return mptcp_get_pernet(sock_net(sk))->close_timeout;
80 : : }
81 : :
82 : 3772 : int mptcp_get_pm_type(const struct net *net)
83 : : {
84 : 3772 : return mptcp_get_pernet(net)->pm_type;
85 : : }
86 : :
87 : 3772 : const char *mptcp_get_path_manager(const struct net *net)
88 : : {
89 : 3772 : return mptcp_get_pernet(net)->path_manager;
90 : : }
91 : :
92 : 2542 : const char *mptcp_get_scheduler(const struct net *net)
93 : : {
94 : 2542 : return mptcp_get_pernet(net)->scheduler;
95 : : }
96 : :
97 : 1106 : static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet)
98 : : {
99 : 1106 : pernet->mptcp_enabled = 1;
100 : 1106 : pernet->add_addr_timeout = TCP_RTO_MAX;
101 : 1106 : pernet->blackhole_timeout = 3600;
102 : 1106 : pernet->syn_retrans_before_tcp_fallback = 2;
103 : 1106 : atomic_set(&pernet->active_disable_times, 0);
104 : 1106 : pernet->close_timeout = TCP_TIMEWAIT_LEN;
105 : 1106 : pernet->checksum_enabled = 0;
106 : 1106 : pernet->allow_join_initial_addr_port = 1;
107 : 1106 : pernet->stale_loss_cnt = 4;
108 : 1106 : pernet->pm_type = MPTCP_PM_TYPE_KERNEL;
109 : 1106 : strscpy(pernet->scheduler, "default", sizeof(pernet->scheduler));
110 : 1106 : strscpy(pernet->path_manager, "kernel", sizeof(pernet->path_manager));
111 : 1106 : }
112 : :
113 : : #ifdef CONFIG_SYSCTL
114 : 36 : static int mptcp_set_scheduler(char *scheduler, const char *name)
115 : : {
116 : 36 : struct mptcp_sched_ops *sched;
117 : 36 : int ret = 0;
118 : :
119 : 36 : rcu_read_lock();
120 : 36 : sched = mptcp_sched_find(name);
121 [ + - ]: 36 : if (sched)
122 : 36 : strscpy(scheduler, name, MPTCP_SCHED_NAME_MAX);
123 : : else
124 : : ret = -ENOENT;
125 : 36 : rcu_read_unlock();
126 : :
127 : 36 : return ret;
128 : : }
129 : :
130 : 44 : static int proc_scheduler(const struct ctl_table *ctl, int write,
131 : : void *buffer, size_t *lenp, loff_t *ppos)
132 : : {
133 : 44 : char (*scheduler)[MPTCP_SCHED_NAME_MAX] = ctl->data;
134 : 44 : char val[MPTCP_SCHED_NAME_MAX];
135 : 44 : struct ctl_table tbl = {
136 : : .data = val,
137 : : .maxlen = MPTCP_SCHED_NAME_MAX,
138 : : };
139 : 44 : int ret;
140 : :
141 : 44 : strscpy(val, *scheduler, MPTCP_SCHED_NAME_MAX);
142 : :
143 : 44 : ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
144 [ + + ]: 44 : if (write && ret == 0)
145 : 36 : ret = mptcp_set_scheduler(*scheduler, val);
146 : :
147 : 44 : return ret;
148 : : }
149 : :
150 : 8 : static int proc_available_schedulers(const struct ctl_table *ctl,
151 : : int write, void *buffer,
152 : : size_t *lenp, loff_t *ppos)
153 : : {
154 : 8 : struct ctl_table tbl = { .maxlen = MPTCP_SCHED_BUF_MAX, };
155 : 8 : int ret;
156 : :
157 : 8 : tbl.data = kmalloc(tbl.maxlen, GFP_USER);
158 [ + - ]: 8 : if (!tbl.data)
159 : : return -ENOMEM;
160 : :
161 : 8 : mptcp_get_available_schedulers(tbl.data, MPTCP_SCHED_BUF_MAX);
162 : 8 : ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
163 : 8 : kfree(tbl.data);
164 : :
165 : 8 : return ret;
166 : : }
167 : :
168 : 8 : static int proc_blackhole_detect_timeout(const struct ctl_table *table,
169 : : int write, void *buffer, size_t *lenp,
170 : : loff_t *ppos)
171 : : {
172 : 8 : struct mptcp_pernet *pernet = container_of(table->data,
173 : : struct mptcp_pernet,
174 : : blackhole_timeout);
175 : 8 : int ret;
176 : :
177 : 8 : ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
178 [ - + ]: 8 : if (write && ret == 0)
179 : 0 : atomic_set(&pernet->active_disable_times, 0);
180 : :
181 : 8 : return ret;
182 : : }
183 : :
184 : 526 : static int mptcp_set_path_manager(char *path_manager, const char *name)
185 : : {
186 : 526 : struct mptcp_pm_ops *pm_ops;
187 : 526 : int ret = 0;
188 : :
189 : 526 : rcu_read_lock();
190 : 526 : pm_ops = mptcp_pm_find(name);
191 [ + + ]: 526 : if (pm_ops)
192 : 524 : strscpy(path_manager, name, MPTCP_PM_NAME_MAX);
193 : : else
194 : : ret = -ENOENT;
195 : 526 : rcu_read_unlock();
196 : :
197 : 526 : return ret;
198 : : }
199 : :
200 : 16 : static int proc_path_manager(const struct ctl_table *ctl, int write,
201 : : void *buffer, size_t *lenp, loff_t *ppos)
202 : : {
203 : 16 : struct mptcp_pernet *pernet = container_of(ctl->data,
204 : : struct mptcp_pernet,
205 : : path_manager);
206 : 16 : char (*path_manager)[MPTCP_PM_NAME_MAX] = ctl->data;
207 : 16 : char pm_name[MPTCP_PM_NAME_MAX];
208 : 16 : const struct ctl_table tbl = {
209 : : .data = pm_name,
210 : : .maxlen = MPTCP_PM_NAME_MAX,
211 : : };
212 : 16 : int ret;
213 : :
214 : 16 : strscpy(pm_name, *path_manager, MPTCP_PM_NAME_MAX);
215 : :
216 : 16 : ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
217 [ + + ]: 16 : if (write && ret == 0) {
218 : 4 : ret = mptcp_set_path_manager(*path_manager, pm_name);
219 [ + + ]: 4 : if (ret == 0) {
220 : 2 : u8 pm_type = __MPTCP_PM_TYPE_NR;
221 : :
222 [ + - ]: 2 : if (strncmp(pm_name, "kernel", MPTCP_PM_NAME_MAX) == 0)
223 : : pm_type = MPTCP_PM_TYPE_KERNEL;
224 [ + - ]: 2 : else if (strncmp(pm_name, "userspace", MPTCP_PM_NAME_MAX) == 0)
225 : 2 : pm_type = MPTCP_PM_TYPE_USERSPACE;
226 : 2 : pernet->pm_type = pm_type;
227 : : }
228 : : }
229 : :
230 : 16 : return ret;
231 : : }
232 : :
233 : 538 : static int proc_pm_type(const struct ctl_table *ctl, int write,
234 : : void *buffer, size_t *lenp, loff_t *ppos)
235 : : {
236 : 538 : struct mptcp_pernet *pernet = container_of(ctl->data,
237 : : struct mptcp_pernet,
238 : : pm_type);
239 : 538 : int ret;
240 : :
241 : 538 : ret = proc_dou8vec_minmax(ctl, write, buffer, lenp, ppos);
242 [ + + ]: 538 : if (write && ret == 0) {
243 : 522 : u8 pm_type = READ_ONCE(*(u8 *)ctl->data);
244 : 522 : char *pm_name = "";
245 : :
246 [ + + ]: 522 : if (pm_type == MPTCP_PM_TYPE_KERNEL)
247 : : pm_name = "kernel";
248 [ + - ]: 28 : else if (pm_type == MPTCP_PM_TYPE_USERSPACE)
249 : 28 : pm_name = "userspace";
250 : 522 : mptcp_set_path_manager(pernet->path_manager, pm_name);
251 : : }
252 : :
253 : 538 : return ret;
254 : : }
255 : :
256 : 8 : static int proc_available_path_managers(const struct ctl_table *ctl,
257 : : int write, void *buffer,
258 : : size_t *lenp, loff_t *ppos)
259 : : {
260 : 8 : struct ctl_table tbl = { .maxlen = MPTCP_PM_BUF_MAX, };
261 : 8 : int ret;
262 : :
263 : 8 : tbl.data = kmalloc(tbl.maxlen, GFP_USER);
264 [ + - ]: 8 : if (!tbl.data)
265 : : return -ENOMEM;
266 : :
267 : 8 : mptcp_pm_get_available(tbl.data, MPTCP_PM_BUF_MAX);
268 : 8 : ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
269 : 8 : kfree(tbl.data);
270 : :
271 : 8 : return ret;
272 : : }
273 : :
274 : : static struct ctl_table mptcp_sysctl_table[] = {
275 : : {
276 : : .procname = "enabled",
277 : : .maxlen = sizeof(u8),
278 : : .mode = 0644,
279 : : /* users with CAP_NET_ADMIN or root (not and) can change this
280 : : * value, same as other sysctl or the 'net' tree.
281 : : */
282 : : .proc_handler = proc_dou8vec_minmax,
283 : : .extra1 = SYSCTL_ZERO,
284 : : .extra2 = SYSCTL_ONE
285 : : },
286 : : {
287 : : .procname = "add_addr_timeout",
288 : : .maxlen = sizeof(unsigned int),
289 : : .mode = 0644,
290 : : .proc_handler = proc_dointvec_jiffies,
291 : : },
292 : : {
293 : : .procname = "checksum_enabled",
294 : : .maxlen = sizeof(u8),
295 : : .mode = 0644,
296 : : .proc_handler = proc_dou8vec_minmax,
297 : : .extra1 = SYSCTL_ZERO,
298 : : .extra2 = SYSCTL_ONE
299 : : },
300 : : {
301 : : .procname = "allow_join_initial_addr_port",
302 : : .maxlen = sizeof(u8),
303 : : .mode = 0644,
304 : : .proc_handler = proc_dou8vec_minmax,
305 : : .extra1 = SYSCTL_ZERO,
306 : : .extra2 = SYSCTL_ONE
307 : : },
308 : : {
309 : : .procname = "stale_loss_cnt",
310 : : .maxlen = sizeof(unsigned int),
311 : : .mode = 0644,
312 : : .proc_handler = proc_douintvec_minmax,
313 : : },
314 : : {
315 : : .procname = "pm_type",
316 : : .maxlen = sizeof(u8),
317 : : .mode = 0644,
318 : : .proc_handler = proc_pm_type,
319 : : .extra1 = SYSCTL_ZERO,
320 : : .extra2 = &mptcp_pm_type_max
321 : : },
322 : : {
323 : : .procname = "scheduler",
324 : : .maxlen = MPTCP_SCHED_NAME_MAX,
325 : : .mode = 0644,
326 : : .proc_handler = proc_scheduler,
327 : : },
328 : : {
329 : : .procname = "available_schedulers",
330 : : .maxlen = MPTCP_SCHED_BUF_MAX,
331 : : .mode = 0444,
332 : : .proc_handler = proc_available_schedulers,
333 : : },
334 : : {
335 : : .procname = "close_timeout",
336 : : .maxlen = sizeof(unsigned int),
337 : : .mode = 0644,
338 : : .proc_handler = proc_dointvec_jiffies,
339 : : },
340 : : {
341 : : .procname = "blackhole_timeout",
342 : : .maxlen = sizeof(unsigned int),
343 : : .mode = 0644,
344 : : .proc_handler = proc_blackhole_detect_timeout,
345 : : .extra1 = SYSCTL_ZERO,
346 : : },
347 : : {
348 : : .procname = "syn_retrans_before_tcp_fallback",
349 : : .maxlen = sizeof(u8),
350 : : .mode = 0644,
351 : : .proc_handler = proc_dou8vec_minmax,
352 : : },
353 : : {
354 : : .procname = "path_manager",
355 : : .maxlen = MPTCP_PM_NAME_MAX,
356 : : .mode = 0644,
357 : : .proc_handler = proc_path_manager,
358 : : },
359 : : {
360 : : .procname = "available_path_managers",
361 : : .maxlen = MPTCP_PM_BUF_MAX,
362 : : .mode = 0444,
363 : : .proc_handler = proc_available_path_managers,
364 : : },
365 : : };
366 : :
367 : 1106 : static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
368 : : {
369 : 1106 : struct ctl_table_header *hdr;
370 : 1106 : struct ctl_table *table;
371 : :
372 : 1106 : table = mptcp_sysctl_table;
373 [ + + ]: 1106 : if (!net_eq(net, &init_net)) {
374 : 1102 : table = kmemdup(table, sizeof(mptcp_sysctl_table), GFP_KERNEL);
375 [ - + ]: 1102 : if (!table)
376 : 0 : goto err_alloc;
377 : : }
378 : :
379 : 1106 : table[0].data = &pernet->mptcp_enabled;
380 : 1106 : table[1].data = &pernet->add_addr_timeout;
381 : 1106 : table[2].data = &pernet->checksum_enabled;
382 : 1106 : table[3].data = &pernet->allow_join_initial_addr_port;
383 : 1106 : table[4].data = &pernet->stale_loss_cnt;
384 : 1106 : table[5].data = &pernet->pm_type;
385 : 1106 : table[6].data = &pernet->scheduler;
386 : : /* table[7] is for available_schedulers which is read-only info */
387 : 1106 : table[8].data = &pernet->close_timeout;
388 : 1106 : table[9].data = &pernet->blackhole_timeout;
389 : 1106 : table[10].data = &pernet->syn_retrans_before_tcp_fallback;
390 : 1106 : table[11].data = &pernet->path_manager;
391 : : /* table[12] is for available_path_managers which is read-only info */
392 : :
393 : 1106 : hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table,
394 : : ARRAY_SIZE(mptcp_sysctl_table));
395 [ - + ]: 1106 : if (!hdr)
396 : 0 : goto err_reg;
397 : :
398 : 1106 : pernet->ctl_table_hdr = hdr;
399 : :
400 : 1106 : return 0;
401 : :
402 : 0 : err_reg:
403 [ # # ]: 0 : if (!net_eq(net, &init_net))
404 : 0 : kfree(table);
405 : 0 : err_alloc:
406 : : return -ENOMEM;
407 : : }
408 : :
409 : 1032 : static void mptcp_pernet_del_table(struct mptcp_pernet *pernet)
410 : : {
411 : 1032 : const struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg;
412 : :
413 : 1032 : unregister_net_sysctl_table(pernet->ctl_table_hdr);
414 : :
415 : 1032 : kfree(table);
416 : 1032 : }
417 : :
418 : : #else
419 : :
420 : : static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
421 : : {
422 : : return 0;
423 : : }
424 : :
425 : : static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {}
426 : :
427 : : #endif /* CONFIG_SYSCTL */
428 : :
429 : : /* The following code block is to deal with middle box issues with MPTCP,
430 : : * similar to what is done with TFO.
431 : : * The proposed solution is to disable active MPTCP globally when SYN+MPC are
432 : : * dropped, while SYN without MPC aren't. In this case, active side MPTCP is
433 : : * disabled globally for 1hr at first. Then if it happens again, it is disabled
434 : : * for 2h, then 4h, 8h, ...
435 : : * The timeout is reset back to 1hr when a successful active MPTCP connection is
436 : : * fully established.
437 : : */
438 : :
439 : : /* Disable active MPTCP and record current jiffies and active_disable_times */
440 : 6 : void mptcp_active_disable(struct sock *sk)
441 : : {
442 : 6 : struct net *net = sock_net(sk);
443 : 6 : struct mptcp_pernet *pernet;
444 : :
445 : 6 : pernet = mptcp_get_pernet(net);
446 : :
447 [ + - ]: 6 : if (!READ_ONCE(pernet->blackhole_timeout))
448 : : return;
449 : :
450 : : /* Paired with READ_ONCE() in mptcp_active_should_disable() */
451 : 6 : WRITE_ONCE(pernet->active_disable_stamp, jiffies);
452 : :
453 : : /* Paired with smp_rmb() in mptcp_active_should_disable().
454 : : * We want pernet->active_disable_stamp to be updated first.
455 : : */
456 : 6 : smp_mb__before_atomic();
457 : 6 : atomic_inc(&pernet->active_disable_times);
458 : :
459 [ + - ]: 6 : MPTCP_INC_STATS(net, MPTCP_MIB_BLACKHOLE);
460 : : }
461 : :
462 : : /* Calculate timeout for MPTCP active disable
463 : : * Return true if we are still in the active MPTCP disable period
464 : : * Return false if timeout already expired and we should use active MPTCP
465 : : */
466 : 1288 : bool mptcp_active_should_disable(struct sock *ssk)
467 : : {
468 : 1288 : struct net *net = sock_net(ssk);
469 : 1288 : unsigned int blackhole_timeout;
470 : 1288 : struct mptcp_pernet *pernet;
471 : 1288 : unsigned long timeout;
472 : 1288 : int disable_times;
473 : 1288 : int multiplier;
474 : :
475 : 1288 : pernet = mptcp_get_pernet(net);
476 : 1288 : blackhole_timeout = READ_ONCE(pernet->blackhole_timeout);
477 : :
478 [ + + ]: 1288 : if (!blackhole_timeout)
479 : : return false;
480 : :
481 [ + + ]: 1288 : disable_times = atomic_read(&pernet->active_disable_times);
482 [ + + ]: 1288 : if (!disable_times)
483 : : return false;
484 : :
485 : : /* Paired with smp_mb__before_atomic() in mptcp_active_disable() */
486 : 6 : smp_rmb();
487 : :
488 : : /* Limit timeout to max: 2^6 * initial timeout */
489 [ - + ]: 6 : multiplier = 1 << min(disable_times - 1, 6);
490 : :
491 : : /* Paired with the WRITE_ONCE() in mptcp_active_disable(). */
492 : 6 : timeout = READ_ONCE(pernet->active_disable_stamp) +
493 : 6 : multiplier * blackhole_timeout * HZ;
494 : :
495 [ - + ]: 6 : return time_before(jiffies, timeout);
496 : : }
497 : :
498 : : /* Enable active MPTCP and reset active_disable_times if needed */
499 : 1130 : void mptcp_active_enable(struct sock *sk)
500 : : {
501 : 1130 : struct mptcp_pernet *pernet = mptcp_get_pernet(sock_net(sk));
502 : :
503 [ - + ]: 1130 : if (atomic_read(&pernet->active_disable_times)) {
504 : 0 : struct dst_entry *dst = sk_dst_get(sk);
505 : :
506 [ # # # # : 0 : if (dst && dst->dev && (dst->dev->flags & IFF_LOOPBACK))
# # ]
507 : 0 : atomic_set(&pernet->active_disable_times, 0);
508 : : }
509 : 1130 : }
510 : :
511 : : /* Check the number of retransmissions, and fallback to TCP if needed */
512 : 828 : void mptcp_active_detect_blackhole(struct sock *ssk, bool expired)
513 : : {
514 : 828 : struct mptcp_subflow_context *subflow;
515 : 828 : u8 timeouts, to_max;
516 : 828 : struct net *net;
517 : :
518 : : /* Only check MPTCP SYN ... */
519 [ + + + + : 828 : if (likely(!sk_is_mptcp(ssk) || ssk->sk_state != TCP_SYN_SENT))
+ + ]
520 : : return;
521 : :
522 [ + + ]: 80 : subflow = mptcp_subflow_ctx(ssk);
523 : :
524 : : /* ... + MP_CAPABLE */
525 [ + + ]: 80 : if (!subflow->request_mptcp) {
526 : : /* Mark as blackhole iif the 1st non-MPTCP SYN is accepted */
527 : 44 : subflow->mpc_drop = 0;
528 : 44 : return;
529 : : }
530 : :
531 : 36 : net = sock_net(ssk);
532 : 36 : timeouts = inet_csk(ssk)->icsk_retransmits;
533 : 36 : to_max = mptcp_get_pernet(net)->syn_retrans_before_tcp_fallback;
534 : :
535 [ + + + + ]: 36 : if (timeouts == to_max || (timeouts < to_max && expired)) {
536 [ + - ]: 18 : MPTCP_INC_STATS(net, MPTCP_MIB_MPCAPABLEACTIVEDROP);
537 : 18 : subflow->mpc_drop = 1;
538 [ - + ]: 18 : mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow);
539 : : }
540 : : }
541 : :
542 : 1106 : static int __net_init mptcp_net_init(struct net *net)
543 : : {
544 : 1106 : struct mptcp_pernet *pernet = mptcp_get_pernet(net);
545 : :
546 : 1106 : mptcp_pernet_set_defaults(pernet);
547 : :
548 : 1106 : return mptcp_pernet_new_table(net, pernet);
549 : : }
550 : :
551 : : /* Note: the callback will only be called per extra netns */
552 : 1032 : static void __net_exit mptcp_net_exit(struct net *net)
553 : : {
554 : 1032 : struct mptcp_pernet *pernet = mptcp_get_pernet(net);
555 : :
556 : 1032 : mptcp_pernet_del_table(pernet);
557 : 1032 : }
558 : :
559 : : static struct pernet_operations mptcp_pernet_ops = {
560 : : .init = mptcp_net_init,
561 : : .exit = mptcp_net_exit,
562 : : .id = &mptcp_pernet_id,
563 : : .size = sizeof(struct mptcp_pernet),
564 : : };
565 : :
566 : 4 : void __init mptcp_init(void)
567 : : {
568 : 4 : mptcp_join_cookie_init();
569 : 4 : mptcp_proto_init();
570 : :
571 [ - + ]: 4 : if (register_pernet_subsys(&mptcp_pernet_ops) < 0)
572 : 0 : panic("Failed to register MPTCP pernet subsystem.\n");
573 : 4 : }
574 : :
575 : : #if IS_ENABLED(CONFIG_MPTCP_IPV6)
576 : 4 : int __init mptcpv6_init(void)
577 : : {
578 : 4 : int err;
579 : :
580 : 4 : err = mptcp_proto_v6_init();
581 : :
582 : 4 : return err;
583 : : }
584 : : #endif
|