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