at v6.6 245 lines 5.3 kB view raw
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 18static int mptcp_pernet_id; 19 20#ifdef CONFIG_SYSCTL 21static int mptcp_pm_type_max = __MPTCP_PM_TYPE_MAX; 22#endif 23 24struct 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 38static struct mptcp_pernet *mptcp_get_pernet(const struct net *net) 39{ 40 return net_generic(net, mptcp_pernet_id); 41} 42 43int mptcp_is_enabled(const struct net *net) 44{ 45 return mptcp_get_pernet(net)->mptcp_enabled; 46} 47 48unsigned int mptcp_get_add_addr_timeout(const struct net *net) 49{ 50 return mptcp_get_pernet(net)->add_addr_timeout; 51} 52 53int mptcp_is_checksum_enabled(const struct net *net) 54{ 55 return mptcp_get_pernet(net)->checksum_enabled; 56} 57 58int mptcp_allow_join_id0(const struct net *net) 59{ 60 return mptcp_get_pernet(net)->allow_join_initial_addr_port; 61} 62 63unsigned int mptcp_stale_loss_cnt(const struct net *net) 64{ 65 return mptcp_get_pernet(net)->stale_loss_cnt; 66} 67 68int mptcp_get_pm_type(const struct net *net) 69{ 70 return mptcp_get_pernet(net)->pm_type; 71} 72 73const char *mptcp_get_scheduler(const struct net *net) 74{ 75 return mptcp_get_pernet(net)->scheduler; 76} 77 78static 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 90static 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 147static 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 176err_reg: 177 if (!net_eq(net, &init_net)) 178 kfree(table); 179err_alloc: 180 return -ENOMEM; 181} 182 183static 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 194static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) 195{ 196 return 0; 197} 198 199static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {} 200 201#endif /* CONFIG_SYSCTL */ 202 203static 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 */ 213static 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 220static 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 227void __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) 237int __init mptcpv6_init(void) 238{ 239 int err; 240 241 err = mptcp_proto_v6_init(); 242 243 return err; 244} 245#endif