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