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