1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * sysctl_net_ipv6.c: sysctl interface to net IPV6 subsystem. 4 * 5 * Changes: 6 * YOSHIFUJI Hideaki @USAGI: added icmp sysctl table. 7 */ 8 9 #include <linux/mm.h> 10 #include <linux/sysctl.h> 11 #include <linux/in6.h> 12 #include <linux/ipv6.h> 13 #include <linux/slab.h> 14 #include <linux/export.h> 15 #include <net/ndisc.h> 16 #include <net/ipv6.h> 17 #include <net/addrconf.h> 18 #include <net/inet_frag.h> 19 #include <net/netevent.h> 20 #include <net/ip_fib.h> 21 #ifdef CONFIG_NETLABEL 22 #include <net/calipso.h> 23 #endif 24 #include <linux/ioam6.h> 25 26 static int flowlabel_reflect_max = 0x7; 27 static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX; 28 static u32 rt6_multipath_hash_fields_all_mask = 29 FIB_MULTIPATH_HASH_FIELD_ALL_MASK; 30 static u32 ioam6_id_max = IOAM6_DEFAULT_ID; 31 static u64 ioam6_id_wide_max = IOAM6_DEFAULT_ID_WIDE; 32 33 static int proc_rt6_multipath_hash_policy(struct ctl_table *table, int write, 34 void *buffer, size_t *lenp, loff_t *ppos) 35 { 36 struct net *net; 37 int ret; 38 39 net = container_of(table->data, struct net, 40 ipv6.sysctl.multipath_hash_policy); 41 ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos); 42 if (write && ret == 0) 43 call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net); 44 45 return ret; 46 } 47 48 static int 49 proc_rt6_multipath_hash_fields(struct ctl_table *table, int write, void *buffer, 50 size_t *lenp, loff_t *ppos) 51 { 52 struct net *net; 53 int ret; 54 55 net = container_of(table->data, struct net, 56 ipv6.sysctl.multipath_hash_fields); 57 ret = proc_douintvec_minmax(table, write, buffer, lenp, ppos); 58 if (write && ret == 0) 59 call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net); 60 61 return ret; 62 } 63 64 static struct ctl_table ipv6_table_template[] = { 65 { 66 .procname = "bindv6only", 67 .data = &init_net.ipv6.sysctl.bindv6only, 68 .maxlen = sizeof(u8), 69 .mode = 0644, 70 .proc_handler = proc_dou8vec_minmax, 71 }, 72 { 73 .procname = "anycast_src_echo_reply", 74 .data = &init_net.ipv6.sysctl.anycast_src_echo_reply, 75 .maxlen = sizeof(u8), 76 .mode = 0644, 77 .proc_handler = proc_dou8vec_minmax, 78 }, 79 { 80 .procname = "flowlabel_consistency", 81 .data = &init_net.ipv6.sysctl.flowlabel_consistency, 82 .maxlen = sizeof(u8), 83 .mode = 0644, 84 .proc_handler = proc_dou8vec_minmax, 85 }, 86 { 87 .procname = "auto_flowlabels", 88 .data = &init_net.ipv6.sysctl.auto_flowlabels, 89 .maxlen = sizeof(u8), 90 .mode = 0644, 91 .proc_handler = proc_dou8vec_minmax, 92 .extra2 = &auto_flowlabels_max 93 }, 94 { 95 .procname = "fwmark_reflect", 96 .data = &init_net.ipv6.sysctl.fwmark_reflect, 97 .maxlen = sizeof(u8), 98 .mode = 0644, 99 .proc_handler = proc_dou8vec_minmax, 100 }, 101 { 102 .procname = "idgen_retries", 103 .data = &init_net.ipv6.sysctl.idgen_retries, 104 .maxlen = sizeof(int), 105 .mode = 0644, 106 .proc_handler = proc_dointvec, 107 }, 108 { 109 .procname = "idgen_delay", 110 .data = &init_net.ipv6.sysctl.idgen_delay, 111 .maxlen = sizeof(int), 112 .mode = 0644, 113 .proc_handler = proc_dointvec_jiffies, 114 }, 115 { 116 .procname = "flowlabel_state_ranges", 117 .data = &init_net.ipv6.sysctl.flowlabel_state_ranges, 118 .maxlen = sizeof(u8), 119 .mode = 0644, 120 .proc_handler = proc_dou8vec_minmax, 121 }, 122 { 123 .procname = "ip_nonlocal_bind", 124 .data = &init_net.ipv6.sysctl.ip_nonlocal_bind, 125 .maxlen = sizeof(u8), 126 .mode = 0644, 127 .proc_handler = proc_dou8vec_minmax, 128 }, 129 { 130 .procname = "flowlabel_reflect", 131 .data = &init_net.ipv6.sysctl.flowlabel_reflect, 132 .maxlen = sizeof(int), 133 .mode = 0644, 134 .proc_handler = proc_dointvec_minmax, 135 .extra1 = SYSCTL_ZERO, 136 .extra2 = &flowlabel_reflect_max, 137 }, 138 { 139 .procname = "max_dst_opts_number", 140 .data = &init_net.ipv6.sysctl.max_dst_opts_cnt, 141 .maxlen = sizeof(int), 142 .mode = 0644, 143 .proc_handler = proc_dointvec 144 }, 145 { 146 .procname = "max_hbh_opts_number", 147 .data = &init_net.ipv6.sysctl.max_hbh_opts_cnt, 148 .maxlen = sizeof(int), 149 .mode = 0644, 150 .proc_handler = proc_dointvec 151 }, 152 { 153 .procname = "max_dst_opts_length", 154 .data = &init_net.ipv6.sysctl.max_dst_opts_len, 155 .maxlen = sizeof(int), 156 .mode = 0644, 157 .proc_handler = proc_dointvec 158 }, 159 { 160 .procname = "max_hbh_length", 161 .data = &init_net.ipv6.sysctl.max_hbh_opts_len, 162 .maxlen = sizeof(int), 163 .mode = 0644, 164 .proc_handler = proc_dointvec 165 }, 166 { 167 .procname = "fib_multipath_hash_policy", 168 .data = &init_net.ipv6.sysctl.multipath_hash_policy, 169 .maxlen = sizeof(u8), 170 .mode = 0644, 171 .proc_handler = proc_rt6_multipath_hash_policy, 172 .extra1 = SYSCTL_ZERO, 173 .extra2 = SYSCTL_THREE, 174 }, 175 { 176 .procname = "fib_multipath_hash_fields", 177 .data = &init_net.ipv6.sysctl.multipath_hash_fields, 178 .maxlen = sizeof(u32), 179 .mode = 0644, 180 .proc_handler = proc_rt6_multipath_hash_fields, 181 .extra1 = SYSCTL_ONE, 182 .extra2 = &rt6_multipath_hash_fields_all_mask, 183 }, 184 { 185 .procname = "seg6_flowlabel", 186 .data = &init_net.ipv6.sysctl.seg6_flowlabel, 187 .maxlen = sizeof(int), 188 .mode = 0644, 189 .proc_handler = proc_dointvec 190 }, 191 { 192 .procname = "fib_notify_on_flag_change", 193 .data = &init_net.ipv6.sysctl.fib_notify_on_flag_change, 194 .maxlen = sizeof(u8), 195 .mode = 0644, 196 .proc_handler = proc_dou8vec_minmax, 197 .extra1 = SYSCTL_ZERO, 198 .extra2 = SYSCTL_TWO, 199 }, 200 { 201 .procname = "ioam6_id", 202 .data = &init_net.ipv6.sysctl.ioam6_id, 203 .maxlen = sizeof(u32), 204 .mode = 0644, 205 .proc_handler = proc_douintvec_minmax, 206 .extra2 = &ioam6_id_max, 207 }, 208 { 209 .procname = "ioam6_id_wide", 210 .data = &init_net.ipv6.sysctl.ioam6_id_wide, 211 .maxlen = sizeof(u64), 212 .mode = 0644, 213 .proc_handler = proc_doulongvec_minmax, 214 .extra2 = &ioam6_id_wide_max, 215 }, 216 { } 217 }; 218 219 static struct ctl_table ipv6_rotable[] = { 220 { 221 .procname = "mld_max_msf", 222 .data = &sysctl_mld_max_msf, 223 .maxlen = sizeof(int), 224 .mode = 0644, 225 .proc_handler = proc_dointvec 226 }, 227 { 228 .procname = "mld_qrv", 229 .data = &sysctl_mld_qrv, 230 .maxlen = sizeof(int), 231 .mode = 0644, 232 .proc_handler = proc_dointvec_minmax, 233 .extra1 = SYSCTL_ONE 234 }, 235 #ifdef CONFIG_NETLABEL 236 { 237 .procname = "calipso_cache_enable", 238 .data = &calipso_cache_enabled, 239 .maxlen = sizeof(int), 240 .mode = 0644, 241 .proc_handler = proc_dointvec, 242 }, 243 { 244 .procname = "calipso_cache_bucket_size", 245 .data = &calipso_cache_bucketsize, 246 .maxlen = sizeof(int), 247 .mode = 0644, 248 .proc_handler = proc_dointvec, 249 }, 250 #endif /* CONFIG_NETLABEL */ 251 { } 252 }; 253 254 static int __net_init ipv6_sysctl_net_init(struct net *net) 255 { 256 struct ctl_table *ipv6_table; 257 struct ctl_table *ipv6_route_table; 258 struct ctl_table *ipv6_icmp_table; 259 int err, i; 260 261 err = -ENOMEM; 262 ipv6_table = kmemdup(ipv6_table_template, sizeof(ipv6_table_template), 263 GFP_KERNEL); 264 if (!ipv6_table) 265 goto out; 266 /* Update the variables to point into the current struct net */ 267 for (i = 0; i < ARRAY_SIZE(ipv6_table_template) - 1; i++) 268 ipv6_table[i].data += (void *)net - (void *)&init_net; 269 270 ipv6_route_table = ipv6_route_sysctl_init(net); 271 if (!ipv6_route_table) 272 goto out_ipv6_table; 273 274 ipv6_icmp_table = ipv6_icmp_sysctl_init(net); 275 if (!ipv6_icmp_table) 276 goto out_ipv6_route_table; 277 278 net->ipv6.sysctl.hdr = register_net_sysctl_sz(net, "net/ipv6", 279 ipv6_table, 280 ARRAY_SIZE(ipv6_table_template)); 281 if (!net->ipv6.sysctl.hdr) 282 goto out_ipv6_icmp_table; 283 284 net->ipv6.sysctl.route_hdr = register_net_sysctl_sz(net, 285 "net/ipv6/route", 286 ipv6_route_table, 287 ipv6_route_sysctl_table_size(net)); 288 if (!net->ipv6.sysctl.route_hdr) 289 goto out_unregister_ipv6_table; 290 291 net->ipv6.sysctl.icmp_hdr = register_net_sysctl_sz(net, 292 "net/ipv6/icmp", 293 ipv6_icmp_table, 294 ipv6_icmp_sysctl_table_size()); 295 if (!net->ipv6.sysctl.icmp_hdr) 296 goto out_unregister_route_table; 297 298 err = 0; 299 out: 300 return err; 301 out_unregister_route_table: 302 unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr); 303 out_unregister_ipv6_table: 304 unregister_net_sysctl_table(net->ipv6.sysctl.hdr); 305 out_ipv6_icmp_table: 306 kfree(ipv6_icmp_table); 307 out_ipv6_route_table: 308 kfree(ipv6_route_table); 309 out_ipv6_table: 310 kfree(ipv6_table); 311 goto out; 312 } 313 314 static void __net_exit ipv6_sysctl_net_exit(struct net *net) 315 { 316 struct ctl_table *ipv6_table; 317 struct ctl_table *ipv6_route_table; 318 struct ctl_table *ipv6_icmp_table; 319 320 ipv6_table = net->ipv6.sysctl.hdr->ctl_table_arg; 321 ipv6_route_table = net->ipv6.sysctl.route_hdr->ctl_table_arg; 322 ipv6_icmp_table = net->ipv6.sysctl.icmp_hdr->ctl_table_arg; 323 324 unregister_net_sysctl_table(net->ipv6.sysctl.icmp_hdr); 325 unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr); 326 unregister_net_sysctl_table(net->ipv6.sysctl.hdr); 327 328 kfree(ipv6_table); 329 kfree(ipv6_route_table); 330 kfree(ipv6_icmp_table); 331 } 332 333 static struct pernet_operations ipv6_sysctl_net_ops = { 334 .init = ipv6_sysctl_net_init, 335 .exit = ipv6_sysctl_net_exit, 336 }; 337 338 static struct ctl_table_header *ip6_header; 339 340 int ipv6_sysctl_register(void) 341 { 342 int err = -ENOMEM; 343 344 ip6_header = register_net_sysctl(&init_net, "net/ipv6", ipv6_rotable); 345 if (!ip6_header) 346 goto out; 347 348 err = register_pernet_subsys(&ipv6_sysctl_net_ops); 349 if (err) 350 goto err_pernet; 351 out: 352 return err; 353 354 err_pernet: 355 unregister_net_sysctl_table(ip6_header); 356 goto out; 357 } 358 359 void ipv6_sysctl_unregister(void) 360 { 361 unregister_net_sysctl_table(ip6_header); 362 unregister_pernet_subsys(&ipv6_sysctl_net_ops); 363 } 364