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 18 static int mptcp_pernet_id; 19 20 #ifdef CONFIG_SYSCTL 21 static int mptcp_pm_type_max = __MPTCP_PM_TYPE_MAX; 22 #endif 23 24 struct 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 38 static struct mptcp_pernet *mptcp_get_pernet(const struct net *net) 39 { 40 return net_generic(net, mptcp_pernet_id); 41 } 42 43 int mptcp_is_enabled(const struct net *net) 44 { 45 return mptcp_get_pernet(net)->mptcp_enabled; 46 } 47 48 unsigned int mptcp_get_add_addr_timeout(const struct net *net) 49 { 50 return mptcp_get_pernet(net)->add_addr_timeout; 51 } 52 53 int mptcp_is_checksum_enabled(const struct net *net) 54 { 55 return mptcp_get_pernet(net)->checksum_enabled; 56 } 57 58 int mptcp_allow_join_id0(const struct net *net) 59 { 60 return mptcp_get_pernet(net)->allow_join_initial_addr_port; 61 } 62 63 unsigned int mptcp_stale_loss_cnt(const struct net *net) 64 { 65 return mptcp_get_pernet(net)->stale_loss_cnt; 66 } 67 68 int mptcp_get_pm_type(const struct net *net) 69 { 70 return mptcp_get_pernet(net)->pm_type; 71 } 72 73 const char *mptcp_get_scheduler(const struct net *net) 74 { 75 return mptcp_get_pernet(net)->scheduler; 76 } 77 78 static 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 90 static int mptcp_set_scheduler(const struct net *net, const char *name) 91 { 92 struct mptcp_pernet *pernet = mptcp_get_pernet(net); 93 struct mptcp_sched_ops *sched; 94 int ret = 0; 95 96 rcu_read_lock(); 97 sched = mptcp_sched_find(name); 98 if (sched) 99 strscpy(pernet->scheduler, name, MPTCP_SCHED_NAME_MAX); 100 else 101 ret = -ENOENT; 102 rcu_read_unlock(); 103 104 return ret; 105 } 106 107 static int proc_scheduler(struct ctl_table *ctl, int write, 108 void *buffer, size_t *lenp, loff_t *ppos) 109 { 110 const struct net *net = current->nsproxy->net_ns; 111 char val[MPTCP_SCHED_NAME_MAX]; 112 struct ctl_table tbl = { 113 .data = val, 114 .maxlen = MPTCP_SCHED_NAME_MAX, 115 }; 116 int ret; 117 118 strscpy(val, mptcp_get_scheduler(net), MPTCP_SCHED_NAME_MAX); 119 120 ret = proc_dostring(&tbl, write, buffer, lenp, ppos); 121 if (write && ret == 0) 122 ret = mptcp_set_scheduler(net, val); 123 124 return ret; 125 } 126 127 static struct ctl_table mptcp_sysctl_table[] = { 128 { 129 .procname = "enabled", 130 .maxlen = sizeof(u8), 131 .mode = 0644, 132 /* users with CAP_NET_ADMIN or root (not and) can change this 133 * value, same as other sysctl or the 'net' tree. 134 */ 135 .proc_handler = proc_dou8vec_minmax, 136 .extra1 = SYSCTL_ZERO, 137 .extra2 = SYSCTL_ONE 138 }, 139 { 140 .procname = "add_addr_timeout", 141 .maxlen = sizeof(unsigned int), 142 .mode = 0644, 143 .proc_handler = proc_dointvec_jiffies, 144 }, 145 { 146 .procname = "checksum_enabled", 147 .maxlen = sizeof(u8), 148 .mode = 0644, 149 .proc_handler = proc_dou8vec_minmax, 150 .extra1 = SYSCTL_ZERO, 151 .extra2 = SYSCTL_ONE 152 }, 153 { 154 .procname = "allow_join_initial_addr_port", 155 .maxlen = sizeof(u8), 156 .mode = 0644, 157 .proc_handler = proc_dou8vec_minmax, 158 .extra1 = SYSCTL_ZERO, 159 .extra2 = SYSCTL_ONE 160 }, 161 { 162 .procname = "stale_loss_cnt", 163 .maxlen = sizeof(unsigned int), 164 .mode = 0644, 165 .proc_handler = proc_douintvec_minmax, 166 }, 167 { 168 .procname = "pm_type", 169 .maxlen = sizeof(u8), 170 .mode = 0644, 171 .proc_handler = proc_dou8vec_minmax, 172 .extra1 = SYSCTL_ZERO, 173 .extra2 = &mptcp_pm_type_max 174 }, 175 { 176 .procname = "scheduler", 177 .maxlen = MPTCP_SCHED_NAME_MAX, 178 .mode = 0644, 179 .proc_handler = proc_scheduler, 180 }, 181 {} 182 }; 183 184 static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) 185 { 186 struct ctl_table_header *hdr; 187 struct ctl_table *table; 188 189 table = mptcp_sysctl_table; 190 if (!net_eq(net, &init_net)) { 191 table = kmemdup(table, sizeof(mptcp_sysctl_table), GFP_KERNEL); 192 if (!table) 193 goto err_alloc; 194 } 195 196 table[0].data = &pernet->mptcp_enabled; 197 table[1].data = &pernet->add_addr_timeout; 198 table[2].data = &pernet->checksum_enabled; 199 table[3].data = &pernet->allow_join_initial_addr_port; 200 table[4].data = &pernet->stale_loss_cnt; 201 table[5].data = &pernet->pm_type; 202 table[6].data = &pernet->scheduler; 203 204 hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table, 205 ARRAY_SIZE(mptcp_sysctl_table)); 206 if (!hdr) 207 goto err_reg; 208 209 pernet->ctl_table_hdr = hdr; 210 211 return 0; 212 213 err_reg: 214 if (!net_eq(net, &init_net)) 215 kfree(table); 216 err_alloc: 217 return -ENOMEM; 218 } 219 220 static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) 221 { 222 struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg; 223 224 unregister_net_sysctl_table(pernet->ctl_table_hdr); 225 226 kfree(table); 227 } 228 229 #else 230 231 static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) 232 { 233 return 0; 234 } 235 236 static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {} 237 238 #endif /* CONFIG_SYSCTL */ 239 240 static int __net_init mptcp_net_init(struct net *net) 241 { 242 struct mptcp_pernet *pernet = mptcp_get_pernet(net); 243 244 mptcp_pernet_set_defaults(pernet); 245 246 return mptcp_pernet_new_table(net, pernet); 247 } 248 249 /* Note: the callback will only be called per extra netns */ 250 static void __net_exit mptcp_net_exit(struct net *net) 251 { 252 struct mptcp_pernet *pernet = mptcp_get_pernet(net); 253 254 mptcp_pernet_del_table(pernet); 255 } 256 257 static struct pernet_operations mptcp_pernet_ops = { 258 .init = mptcp_net_init, 259 .exit = mptcp_net_exit, 260 .id = &mptcp_pernet_id, 261 .size = sizeof(struct mptcp_pernet), 262 }; 263 264 void __init mptcp_init(void) 265 { 266 mptcp_join_cookie_init(); 267 mptcp_proto_init(); 268 269 if (register_pernet_subsys(&mptcp_pernet_ops) < 0) 270 panic("Failed to register MPTCP pernet subsystem.\n"); 271 } 272 273 #if IS_ENABLED(CONFIG_MPTCP_IPV6) 274 int __init mptcpv6_init(void) 275 { 276 int err; 277 278 err = mptcp_proto_v6_init(); 279 280 return err; 281 } 282 #endif 283