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 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 147 static 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(net, MPTCP_SYSCTL_PATH, table); 168 if (!hdr) 169 goto err_reg; 170 171 pernet->ctl_table_hdr = hdr; 172 173 return 0; 174 175 err_reg: 176 if (!net_eq(net, &init_net)) 177 kfree(table); 178 err_alloc: 179 return -ENOMEM; 180 } 181 182 static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) 183 { 184 struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg; 185 186 unregister_net_sysctl_table(pernet->ctl_table_hdr); 187 188 kfree(table); 189 } 190 191 #else 192 193 static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) 194 { 195 return 0; 196 } 197 198 static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {} 199 200 #endif /* CONFIG_SYSCTL */ 201 202 static int __net_init mptcp_net_init(struct net *net) 203 { 204 struct mptcp_pernet *pernet = mptcp_get_pernet(net); 205 206 mptcp_pernet_set_defaults(pernet); 207 208 return mptcp_pernet_new_table(net, pernet); 209 } 210 211 /* Note: the callback will only be called per extra netns */ 212 static void __net_exit mptcp_net_exit(struct net *net) 213 { 214 struct mptcp_pernet *pernet = mptcp_get_pernet(net); 215 216 mptcp_pernet_del_table(pernet); 217 } 218 219 static struct pernet_operations mptcp_pernet_ops = { 220 .init = mptcp_net_init, 221 .exit = mptcp_net_exit, 222 .id = &mptcp_pernet_id, 223 .size = sizeof(struct mptcp_pernet), 224 }; 225 226 void __init mptcp_init(void) 227 { 228 mptcp_join_cookie_init(); 229 mptcp_proto_init(); 230 231 if (register_pernet_subsys(&mptcp_pernet_ops) < 0) 232 panic("Failed to register MPTCP pernet subsystem.\n"); 233 } 234 235 #if IS_ENABLED(CONFIG_MPTCP_IPV6) 236 int __init mptcpv6_init(void) 237 { 238 int err; 239 240 err = mptcp_proto_v6_init(); 241 242 return err; 243 } 244 #endif 245