]>
Commit | Line | Data |
---|---|---|
784325e9 MB |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Multipath TCP | |
3 | * | |
4 | * Copyright (c) 2019, Tessares SA. | |
5 | */ | |
6 | ||
7 | #include <linux/sysctl.h> | |
8 | ||
9 | #include <net/net_namespace.h> | |
10 | #include <net/netns/generic.h> | |
11 | ||
12 | #include "protocol.h" | |
13 | ||
14 | #define MPTCP_SYSCTL_PATH "net/mptcp" | |
15 | ||
16 | static int mptcp_pernet_id; | |
17 | struct mptcp_pernet { | |
18 | struct ctl_table_header *ctl_table_hdr; | |
19 | ||
20 | int mptcp_enabled; | |
21 | }; | |
22 | ||
23 | static struct mptcp_pernet *mptcp_get_pernet(struct net *net) | |
24 | { | |
25 | return net_generic(net, mptcp_pernet_id); | |
26 | } | |
27 | ||
28 | int mptcp_is_enabled(struct net *net) | |
29 | { | |
30 | return mptcp_get_pernet(net)->mptcp_enabled; | |
31 | } | |
32 | ||
33 | static struct ctl_table mptcp_sysctl_table[] = { | |
34 | { | |
35 | .procname = "enabled", | |
36 | .maxlen = sizeof(int), | |
37 | .mode = 0644, | |
38 | /* users with CAP_NET_ADMIN or root (not and) can change this | |
39 | * value, same as other sysctl or the 'net' tree. | |
40 | */ | |
41 | .proc_handler = proc_dointvec, | |
42 | }, | |
43 | {} | |
44 | }; | |
45 | ||
46 | static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet) | |
47 | { | |
48 | pernet->mptcp_enabled = 1; | |
49 | } | |
50 | ||
51 | static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) | |
52 | { | |
53 | struct ctl_table_header *hdr; | |
54 | struct ctl_table *table; | |
55 | ||
56 | table = mptcp_sysctl_table; | |
57 | if (!net_eq(net, &init_net)) { | |
58 | table = kmemdup(table, sizeof(mptcp_sysctl_table), GFP_KERNEL); | |
59 | if (!table) | |
60 | goto err_alloc; | |
61 | } | |
62 | ||
63 | table[0].data = &pernet->mptcp_enabled; | |
64 | ||
65 | hdr = register_net_sysctl(net, MPTCP_SYSCTL_PATH, table); | |
66 | if (!hdr) | |
67 | goto err_reg; | |
68 | ||
69 | pernet->ctl_table_hdr = hdr; | |
70 | ||
71 | return 0; | |
72 | ||
73 | err_reg: | |
74 | if (!net_eq(net, &init_net)) | |
75 | kfree(table); | |
76 | err_alloc: | |
77 | return -ENOMEM; | |
78 | } | |
79 | ||
80 | static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) | |
81 | { | |
82 | struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg; | |
83 | ||
84 | unregister_net_sysctl_table(pernet->ctl_table_hdr); | |
85 | ||
86 | kfree(table); | |
87 | } | |
88 | ||
89 | static int __net_init mptcp_net_init(struct net *net) | |
90 | { | |
91 | struct mptcp_pernet *pernet = mptcp_get_pernet(net); | |
92 | ||
93 | mptcp_pernet_set_defaults(pernet); | |
94 | ||
95 | return mptcp_pernet_new_table(net, pernet); | |
96 | } | |
97 | ||
98 | /* Note: the callback will only be called per extra netns */ | |
99 | static void __net_exit mptcp_net_exit(struct net *net) | |
100 | { | |
101 | struct mptcp_pernet *pernet = mptcp_get_pernet(net); | |
102 | ||
103 | mptcp_pernet_del_table(pernet); | |
104 | } | |
105 | ||
106 | static struct pernet_operations mptcp_pernet_ops = { | |
107 | .init = mptcp_net_init, | |
108 | .exit = mptcp_net_exit, | |
109 | .id = &mptcp_pernet_id, | |
110 | .size = sizeof(struct mptcp_pernet), | |
111 | }; | |
112 | ||
113 | void __init mptcp_init(void) | |
114 | { | |
115 | mptcp_proto_init(); | |
116 | ||
117 | if (register_pernet_subsys(&mptcp_pernet_ops) < 0) | |
118 | panic("Failed to register MPTCP pernet subsystem.\n"); | |
119 | } | |
120 | ||
121 | #if IS_ENABLED(CONFIG_MPTCP_IPV6) | |
122 | int __init mptcpv6_init(void) | |
123 | { | |
124 | int err; | |
125 | ||
126 | err = mptcp_proto_v6_init(); | |
127 | ||
128 | return err; | |
129 | } | |
130 | #endif |