0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/mm.h>
0010 #include <linux/sysctl.h>
0011 #include <linux/in6.h>
0012 #include <linux/ipv6.h>
0013 #include <linux/slab.h>
0014 #include <linux/export.h>
0015 #include <net/ndisc.h>
0016 #include <net/ipv6.h>
0017 #include <net/addrconf.h>
0018 #include <net/inet_frag.h>
0019 #include <net/netevent.h>
0020 #include <net/ip_fib.h>
0021 #ifdef CONFIG_NETLABEL
0022 #include <net/calipso.h>
0023 #endif
0024 #include <linux/ioam6.h>
0025
0026 static int flowlabel_reflect_max = 0x7;
0027 static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
0028 static u32 rt6_multipath_hash_fields_all_mask =
0029 FIB_MULTIPATH_HASH_FIELD_ALL_MASK;
0030 static u32 ioam6_id_max = IOAM6_DEFAULT_ID;
0031 static u64 ioam6_id_wide_max = IOAM6_DEFAULT_ID_WIDE;
0032
0033 static int proc_rt6_multipath_hash_policy(struct ctl_table *table, int write,
0034 void *buffer, size_t *lenp, loff_t *ppos)
0035 {
0036 struct net *net;
0037 int ret;
0038
0039 net = container_of(table->data, struct net,
0040 ipv6.sysctl.multipath_hash_policy);
0041 ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos);
0042 if (write && ret == 0)
0043 call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net);
0044
0045 return ret;
0046 }
0047
0048 static int
0049 proc_rt6_multipath_hash_fields(struct ctl_table *table, int write, void *buffer,
0050 size_t *lenp, loff_t *ppos)
0051 {
0052 struct net *net;
0053 int ret;
0054
0055 net = container_of(table->data, struct net,
0056 ipv6.sysctl.multipath_hash_fields);
0057 ret = proc_douintvec_minmax(table, write, buffer, lenp, ppos);
0058 if (write && ret == 0)
0059 call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net);
0060
0061 return ret;
0062 }
0063
0064 static struct ctl_table ipv6_table_template[] = {
0065 {
0066 .procname = "bindv6only",
0067 .data = &init_net.ipv6.sysctl.bindv6only,
0068 .maxlen = sizeof(u8),
0069 .mode = 0644,
0070 .proc_handler = proc_dou8vec_minmax,
0071 },
0072 {
0073 .procname = "anycast_src_echo_reply",
0074 .data = &init_net.ipv6.sysctl.anycast_src_echo_reply,
0075 .maxlen = sizeof(u8),
0076 .mode = 0644,
0077 .proc_handler = proc_dou8vec_minmax,
0078 },
0079 {
0080 .procname = "flowlabel_consistency",
0081 .data = &init_net.ipv6.sysctl.flowlabel_consistency,
0082 .maxlen = sizeof(u8),
0083 .mode = 0644,
0084 .proc_handler = proc_dou8vec_minmax,
0085 },
0086 {
0087 .procname = "auto_flowlabels",
0088 .data = &init_net.ipv6.sysctl.auto_flowlabels,
0089 .maxlen = sizeof(u8),
0090 .mode = 0644,
0091 .proc_handler = proc_dou8vec_minmax,
0092 .extra2 = &auto_flowlabels_max
0093 },
0094 {
0095 .procname = "fwmark_reflect",
0096 .data = &init_net.ipv6.sysctl.fwmark_reflect,
0097 .maxlen = sizeof(u8),
0098 .mode = 0644,
0099 .proc_handler = proc_dou8vec_minmax,
0100 },
0101 {
0102 .procname = "idgen_retries",
0103 .data = &init_net.ipv6.sysctl.idgen_retries,
0104 .maxlen = sizeof(int),
0105 .mode = 0644,
0106 .proc_handler = proc_dointvec,
0107 },
0108 {
0109 .procname = "idgen_delay",
0110 .data = &init_net.ipv6.sysctl.idgen_delay,
0111 .maxlen = sizeof(int),
0112 .mode = 0644,
0113 .proc_handler = proc_dointvec_jiffies,
0114 },
0115 {
0116 .procname = "flowlabel_state_ranges",
0117 .data = &init_net.ipv6.sysctl.flowlabel_state_ranges,
0118 .maxlen = sizeof(u8),
0119 .mode = 0644,
0120 .proc_handler = proc_dou8vec_minmax,
0121 },
0122 {
0123 .procname = "ip_nonlocal_bind",
0124 .data = &init_net.ipv6.sysctl.ip_nonlocal_bind,
0125 .maxlen = sizeof(u8),
0126 .mode = 0644,
0127 .proc_handler = proc_dou8vec_minmax,
0128 },
0129 {
0130 .procname = "flowlabel_reflect",
0131 .data = &init_net.ipv6.sysctl.flowlabel_reflect,
0132 .maxlen = sizeof(int),
0133 .mode = 0644,
0134 .proc_handler = proc_dointvec_minmax,
0135 .extra1 = SYSCTL_ZERO,
0136 .extra2 = &flowlabel_reflect_max,
0137 },
0138 {
0139 .procname = "max_dst_opts_number",
0140 .data = &init_net.ipv6.sysctl.max_dst_opts_cnt,
0141 .maxlen = sizeof(int),
0142 .mode = 0644,
0143 .proc_handler = proc_dointvec
0144 },
0145 {
0146 .procname = "max_hbh_opts_number",
0147 .data = &init_net.ipv6.sysctl.max_hbh_opts_cnt,
0148 .maxlen = sizeof(int),
0149 .mode = 0644,
0150 .proc_handler = proc_dointvec
0151 },
0152 {
0153 .procname = "max_dst_opts_length",
0154 .data = &init_net.ipv6.sysctl.max_dst_opts_len,
0155 .maxlen = sizeof(int),
0156 .mode = 0644,
0157 .proc_handler = proc_dointvec
0158 },
0159 {
0160 .procname = "max_hbh_length",
0161 .data = &init_net.ipv6.sysctl.max_hbh_opts_len,
0162 .maxlen = sizeof(int),
0163 .mode = 0644,
0164 .proc_handler = proc_dointvec
0165 },
0166 {
0167 .procname = "fib_multipath_hash_policy",
0168 .data = &init_net.ipv6.sysctl.multipath_hash_policy,
0169 .maxlen = sizeof(u8),
0170 .mode = 0644,
0171 .proc_handler = proc_rt6_multipath_hash_policy,
0172 .extra1 = SYSCTL_ZERO,
0173 .extra2 = SYSCTL_THREE,
0174 },
0175 {
0176 .procname = "fib_multipath_hash_fields",
0177 .data = &init_net.ipv6.sysctl.multipath_hash_fields,
0178 .maxlen = sizeof(u32),
0179 .mode = 0644,
0180 .proc_handler = proc_rt6_multipath_hash_fields,
0181 .extra1 = SYSCTL_ONE,
0182 .extra2 = &rt6_multipath_hash_fields_all_mask,
0183 },
0184 {
0185 .procname = "seg6_flowlabel",
0186 .data = &init_net.ipv6.sysctl.seg6_flowlabel,
0187 .maxlen = sizeof(int),
0188 .mode = 0644,
0189 .proc_handler = proc_dointvec
0190 },
0191 {
0192 .procname = "fib_notify_on_flag_change",
0193 .data = &init_net.ipv6.sysctl.fib_notify_on_flag_change,
0194 .maxlen = sizeof(u8),
0195 .mode = 0644,
0196 .proc_handler = proc_dou8vec_minmax,
0197 .extra1 = SYSCTL_ZERO,
0198 .extra2 = SYSCTL_TWO,
0199 },
0200 {
0201 .procname = "ioam6_id",
0202 .data = &init_net.ipv6.sysctl.ioam6_id,
0203 .maxlen = sizeof(u32),
0204 .mode = 0644,
0205 .proc_handler = proc_douintvec_minmax,
0206 .extra2 = &ioam6_id_max,
0207 },
0208 {
0209 .procname = "ioam6_id_wide",
0210 .data = &init_net.ipv6.sysctl.ioam6_id_wide,
0211 .maxlen = sizeof(u64),
0212 .mode = 0644,
0213 .proc_handler = proc_doulongvec_minmax,
0214 .extra2 = &ioam6_id_wide_max,
0215 },
0216 { }
0217 };
0218
0219 static struct ctl_table ipv6_rotable[] = {
0220 {
0221 .procname = "mld_max_msf",
0222 .data = &sysctl_mld_max_msf,
0223 .maxlen = sizeof(int),
0224 .mode = 0644,
0225 .proc_handler = proc_dointvec
0226 },
0227 {
0228 .procname = "mld_qrv",
0229 .data = &sysctl_mld_qrv,
0230 .maxlen = sizeof(int),
0231 .mode = 0644,
0232 .proc_handler = proc_dointvec_minmax,
0233 .extra1 = SYSCTL_ONE
0234 },
0235 #ifdef CONFIG_NETLABEL
0236 {
0237 .procname = "calipso_cache_enable",
0238 .data = &calipso_cache_enabled,
0239 .maxlen = sizeof(int),
0240 .mode = 0644,
0241 .proc_handler = proc_dointvec,
0242 },
0243 {
0244 .procname = "calipso_cache_bucket_size",
0245 .data = &calipso_cache_bucketsize,
0246 .maxlen = sizeof(int),
0247 .mode = 0644,
0248 .proc_handler = proc_dointvec,
0249 },
0250 #endif
0251 { }
0252 };
0253
0254 static int __net_init ipv6_sysctl_net_init(struct net *net)
0255 {
0256 struct ctl_table *ipv6_table;
0257 struct ctl_table *ipv6_route_table;
0258 struct ctl_table *ipv6_icmp_table;
0259 int err, i;
0260
0261 err = -ENOMEM;
0262 ipv6_table = kmemdup(ipv6_table_template, sizeof(ipv6_table_template),
0263 GFP_KERNEL);
0264 if (!ipv6_table)
0265 goto out;
0266
0267 for (i = 0; i < ARRAY_SIZE(ipv6_table_template) - 1; i++)
0268 ipv6_table[i].data += (void *)net - (void *)&init_net;
0269
0270 ipv6_route_table = ipv6_route_sysctl_init(net);
0271 if (!ipv6_route_table)
0272 goto out_ipv6_table;
0273
0274 ipv6_icmp_table = ipv6_icmp_sysctl_init(net);
0275 if (!ipv6_icmp_table)
0276 goto out_ipv6_route_table;
0277
0278 net->ipv6.sysctl.hdr = register_net_sysctl(net, "net/ipv6", ipv6_table);
0279 if (!net->ipv6.sysctl.hdr)
0280 goto out_ipv6_icmp_table;
0281
0282 net->ipv6.sysctl.route_hdr =
0283 register_net_sysctl(net, "net/ipv6/route", ipv6_route_table);
0284 if (!net->ipv6.sysctl.route_hdr)
0285 goto out_unregister_ipv6_table;
0286
0287 net->ipv6.sysctl.icmp_hdr =
0288 register_net_sysctl(net, "net/ipv6/icmp", ipv6_icmp_table);
0289 if (!net->ipv6.sysctl.icmp_hdr)
0290 goto out_unregister_route_table;
0291
0292 err = 0;
0293 out:
0294 return err;
0295 out_unregister_route_table:
0296 unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
0297 out_unregister_ipv6_table:
0298 unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
0299 out_ipv6_icmp_table:
0300 kfree(ipv6_icmp_table);
0301 out_ipv6_route_table:
0302 kfree(ipv6_route_table);
0303 out_ipv6_table:
0304 kfree(ipv6_table);
0305 goto out;
0306 }
0307
0308 static void __net_exit ipv6_sysctl_net_exit(struct net *net)
0309 {
0310 struct ctl_table *ipv6_table;
0311 struct ctl_table *ipv6_route_table;
0312 struct ctl_table *ipv6_icmp_table;
0313
0314 ipv6_table = net->ipv6.sysctl.hdr->ctl_table_arg;
0315 ipv6_route_table = net->ipv6.sysctl.route_hdr->ctl_table_arg;
0316 ipv6_icmp_table = net->ipv6.sysctl.icmp_hdr->ctl_table_arg;
0317
0318 unregister_net_sysctl_table(net->ipv6.sysctl.icmp_hdr);
0319 unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
0320 unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
0321
0322 kfree(ipv6_table);
0323 kfree(ipv6_route_table);
0324 kfree(ipv6_icmp_table);
0325 }
0326
0327 static struct pernet_operations ipv6_sysctl_net_ops = {
0328 .init = ipv6_sysctl_net_init,
0329 .exit = ipv6_sysctl_net_exit,
0330 };
0331
0332 static struct ctl_table_header *ip6_header;
0333
0334 int ipv6_sysctl_register(void)
0335 {
0336 int err = -ENOMEM;
0337
0338 ip6_header = register_net_sysctl(&init_net, "net/ipv6", ipv6_rotable);
0339 if (!ip6_header)
0340 goto out;
0341
0342 err = register_pernet_subsys(&ipv6_sysctl_net_ops);
0343 if (err)
0344 goto err_pernet;
0345 out:
0346 return err;
0347
0348 err_pernet:
0349 unregister_net_sysctl_table(ip6_header);
0350 goto out;
0351 }
0352
0353 void ipv6_sysctl_unregister(void)
0354 {
0355 unregister_net_sysctl_table(ip6_header);
0356 unregister_pernet_subsys(&ipv6_sysctl_net_ops);
0357 }