Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * sysctl_net_ipv6.c: sysctl interface to net IPV6 subsystem.
0004  *
0005  * Changes:
0006  * YOSHIFUJI Hideaki @USAGI:    added icmp sysctl table.
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 /* CONFIG_NETLABEL */
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     /* Update the variables to point into the current struct net */
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 }