linux/net/mptcp/ctrl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Multipath TCP
   3 *
   4 * Copyright (c) 2019, Tessares SA.
   5 */
   6
   7#ifdef CONFIG_SYSCTL
   8#include <linux/sysctl.h>
   9#endif
  10
  11#include <net/net_namespace.h>
  12#include <net/netns/generic.h>
  13
  14#include "protocol.h"
  15
  16#define MPTCP_SYSCTL_PATH "net/mptcp"
  17
  18static int mptcp_pernet_id;
  19struct mptcp_pernet {
  20#ifdef CONFIG_SYSCTL
  21        struct ctl_table_header *ctl_table_hdr;
  22#endif
  23
  24        u8 mptcp_enabled;
  25        unsigned int add_addr_timeout;
  26        u8 checksum_enabled;
  27        u8 allow_join_initial_addr_port;
  28};
  29
  30static struct mptcp_pernet *mptcp_get_pernet(struct net *net)
  31{
  32        return net_generic(net, mptcp_pernet_id);
  33}
  34
  35int mptcp_is_enabled(struct net *net)
  36{
  37        return mptcp_get_pernet(net)->mptcp_enabled;
  38}
  39
  40unsigned int mptcp_get_add_addr_timeout(struct net *net)
  41{
  42        return mptcp_get_pernet(net)->add_addr_timeout;
  43}
  44
  45int mptcp_is_checksum_enabled(struct net *net)
  46{
  47        return mptcp_get_pernet(net)->checksum_enabled;
  48}
  49
  50int mptcp_allow_join_id0(struct net *net)
  51{
  52        return mptcp_get_pernet(net)->allow_join_initial_addr_port;
  53}
  54
  55static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet)
  56{
  57        pernet->mptcp_enabled = 1;
  58        pernet->add_addr_timeout = TCP_RTO_MAX;
  59        pernet->checksum_enabled = 0;
  60        pernet->allow_join_initial_addr_port = 1;
  61}
  62
  63#ifdef CONFIG_SYSCTL
  64static struct ctl_table mptcp_sysctl_table[] = {
  65        {
  66                .procname = "enabled",
  67                .maxlen = sizeof(u8),
  68                .mode = 0644,
  69                /* users with CAP_NET_ADMIN or root (not and) can change this
  70                 * value, same as other sysctl or the 'net' tree.
  71                 */
  72                .proc_handler = proc_dou8vec_minmax,
  73                .extra1       = SYSCTL_ZERO,
  74                .extra2       = SYSCTL_ONE
  75        },
  76        {
  77                .procname = "add_addr_timeout",
  78                .maxlen = sizeof(unsigned int),
  79                .mode = 0644,
  80                .proc_handler = proc_dointvec_jiffies,
  81        },
  82        {
  83                .procname = "checksum_enabled",
  84                .maxlen = sizeof(u8),
  85                .mode = 0644,
  86                .proc_handler = proc_dou8vec_minmax,
  87                .extra1       = SYSCTL_ZERO,
  88                .extra2       = SYSCTL_ONE
  89        },
  90        {
  91                .procname = "allow_join_initial_addr_port",
  92                .maxlen = sizeof(u8),
  93                .mode = 0644,
  94                .proc_handler = proc_dou8vec_minmax,
  95                .extra1       = SYSCTL_ZERO,
  96                .extra2       = SYSCTL_ONE
  97        },
  98        {}
  99};
 100
 101static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
 102{
 103        struct ctl_table_header *hdr;
 104        struct ctl_table *table;
 105
 106        table = mptcp_sysctl_table;
 107        if (!net_eq(net, &init_net)) {
 108                table = kmemdup(table, sizeof(mptcp_sysctl_table), GFP_KERNEL);
 109                if (!table)
 110                        goto err_alloc;
 111        }
 112
 113        table[0].data = &pernet->mptcp_enabled;
 114        table[1].data = &pernet->add_addr_timeout;
 115        table[2].data = &pernet->checksum_enabled;
 116        table[3].data = &pernet->allow_join_initial_addr_port;
 117
 118        hdr = register_net_sysctl(net, MPTCP_SYSCTL_PATH, table);
 119        if (!hdr)
 120                goto err_reg;
 121
 122        pernet->ctl_table_hdr = hdr;
 123
 124        return 0;
 125
 126err_reg:
 127        if (!net_eq(net, &init_net))
 128                kfree(table);
 129err_alloc:
 130        return -ENOMEM;
 131}
 132
 133static void mptcp_pernet_del_table(struct mptcp_pernet *pernet)
 134{
 135        struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg;
 136
 137        unregister_net_sysctl_table(pernet->ctl_table_hdr);
 138
 139        kfree(table);
 140}
 141
 142#else
 143
 144static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
 145{
 146        return 0;
 147}
 148
 149static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {}
 150
 151#endif /* CONFIG_SYSCTL */
 152
 153static int __net_init mptcp_net_init(struct net *net)
 154{
 155        struct mptcp_pernet *pernet = mptcp_get_pernet(net);
 156
 157        mptcp_pernet_set_defaults(pernet);
 158
 159        return mptcp_pernet_new_table(net, pernet);
 160}
 161
 162/* Note: the callback will only be called per extra netns */
 163static void __net_exit mptcp_net_exit(struct net *net)
 164{
 165        struct mptcp_pernet *pernet = mptcp_get_pernet(net);
 166
 167        mptcp_pernet_del_table(pernet);
 168}
 169
 170static struct pernet_operations mptcp_pernet_ops = {
 171        .init = mptcp_net_init,
 172        .exit = mptcp_net_exit,
 173        .id = &mptcp_pernet_id,
 174        .size = sizeof(struct mptcp_pernet),
 175};
 176
 177void __init mptcp_init(void)
 178{
 179        mptcp_join_cookie_init();
 180        mptcp_proto_init();
 181
 182        if (register_pernet_subsys(&mptcp_pernet_ops) < 0)
 183                panic("Failed to register MPTCP pernet subsystem.\n");
 184}
 185
 186#if IS_ENABLED(CONFIG_MPTCP_IPV6)
 187int __init mptcpv6_init(void)
 188{
 189        int err;
 190
 191        err = mptcp_proto_v6_init();
 192
 193        return err;
 194}
 195#endif
 196