]> git.baikalelectronics.ru Git - kernel.git/commitdiff
mptcp: new sysctl to control the activation per NS
authorMatthieu Baerts <matthieu.baerts@tessares.net>
Wed, 22 Jan 2020 00:56:28 +0000 (16:56 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 24 Jan 2020 12:44:08 +0000 (13:44 +0100)
New MPTCP sockets will return -ENOPROTOOPT if MPTCP support is disabled
for the current net namespace.

We are providing here a way to control access to the feature for those
that need to turn it on or off.

The value of this new sysctl can be different per namespace. We can then
restrict the usage of MPTCP to the selected NS. In case of serious
issues with MPTCP, administrators can now easily turn MPTCP off.

Co-developed-by: Peter Krystad <peter.krystad@linux.intel.com>
Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Christoph Paasch <cpaasch@apple.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/mptcp/Makefile
net/mptcp/ctrl.c [new file with mode: 0644]
net/mptcp/protocol.c
net/mptcp/protocol.h

index 178ae81d8b66970e192794612c1d6543701750ce..4e98d9edfd0a33ade40024ee44225f79a7ac9bf1 100644 (file)
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_MPTCP) += mptcp.o
 
-mptcp-y := protocol.o subflow.o options.o token.o crypto.o
+mptcp-y := protocol.o subflow.o options.o token.o crypto.o ctrl.o
diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c
new file mode 100644 (file)
index 0000000..8e39585
--- /dev/null
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Multipath TCP
+ *
+ * Copyright (c) 2019, Tessares SA.
+ */
+
+#include <linux/sysctl.h>
+
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+#include "protocol.h"
+
+#define MPTCP_SYSCTL_PATH "net/mptcp"
+
+static int mptcp_pernet_id;
+struct mptcp_pernet {
+       struct ctl_table_header *ctl_table_hdr;
+
+       int mptcp_enabled;
+};
+
+static struct mptcp_pernet *mptcp_get_pernet(struct net *net)
+{
+       return net_generic(net, mptcp_pernet_id);
+}
+
+int mptcp_is_enabled(struct net *net)
+{
+       return mptcp_get_pernet(net)->mptcp_enabled;
+}
+
+static struct ctl_table mptcp_sysctl_table[] = {
+       {
+               .procname = "enabled",
+               .maxlen = sizeof(int),
+               .mode = 0644,
+               /* users with CAP_NET_ADMIN or root (not and) can change this
+                * value, same as other sysctl or the 'net' tree.
+                */
+               .proc_handler = proc_dointvec,
+       },
+       {}
+};
+
+static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet)
+{
+       pernet->mptcp_enabled = 1;
+}
+
+static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
+{
+       struct ctl_table_header *hdr;
+       struct ctl_table *table;
+
+       table = mptcp_sysctl_table;
+       if (!net_eq(net, &init_net)) {
+               table = kmemdup(table, sizeof(mptcp_sysctl_table), GFP_KERNEL);
+               if (!table)
+                       goto err_alloc;
+       }
+
+       table[0].data = &pernet->mptcp_enabled;
+
+       hdr = register_net_sysctl(net, MPTCP_SYSCTL_PATH, table);
+       if (!hdr)
+               goto err_reg;
+
+       pernet->ctl_table_hdr = hdr;
+
+       return 0;
+
+err_reg:
+       if (!net_eq(net, &init_net))
+               kfree(table);
+err_alloc:
+       return -ENOMEM;
+}
+
+static void mptcp_pernet_del_table(struct mptcp_pernet *pernet)
+{
+       struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg;
+
+       unregister_net_sysctl_table(pernet->ctl_table_hdr);
+
+       kfree(table);
+}
+
+static int __net_init mptcp_net_init(struct net *net)
+{
+       struct mptcp_pernet *pernet = mptcp_get_pernet(net);
+
+       mptcp_pernet_set_defaults(pernet);
+
+       return mptcp_pernet_new_table(net, pernet);
+}
+
+/* Note: the callback will only be called per extra netns */
+static void __net_exit mptcp_net_exit(struct net *net)
+{
+       struct mptcp_pernet *pernet = mptcp_get_pernet(net);
+
+       mptcp_pernet_del_table(pernet);
+}
+
+static struct pernet_operations mptcp_pernet_ops = {
+       .init = mptcp_net_init,
+       .exit = mptcp_net_exit,
+       .id = &mptcp_pernet_id,
+       .size = sizeof(struct mptcp_pernet),
+};
+
+void __init mptcp_init(void)
+{
+       mptcp_proto_init();
+
+       if (register_pernet_subsys(&mptcp_pernet_ops) < 0)
+               panic("Failed to register MPTCP pernet subsystem.\n");
+}
+
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+int __init mptcpv6_init(void)
+{
+       int err;
+
+       err = mptcp_proto_v6_init();
+
+       return err;
+}
+#endif
index 0b21ae25bd0f990737fd2a2aa39905812c1f5dab..45e482864a195cbbf5409c85ab98f11dca44526b 100644 (file)
@@ -522,7 +522,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
        }
 }
 
-static int mptcp_init_sock(struct sock *sk)
+static int __mptcp_init_sock(struct sock *sk)
 {
        struct mptcp_sock *msk = mptcp_sk(sk);
 
@@ -532,6 +532,14 @@ static int mptcp_init_sock(struct sock *sk)
        return 0;
 }
 
+static int mptcp_init_sock(struct sock *sk)
+{
+       if (!mptcp_is_enabled(sock_net(sk)))
+               return -ENOPROTOOPT;
+
+       return __mptcp_init_sock(sk);
+}
+
 static void mptcp_subflow_shutdown(struct sock *ssk, int how)
 {
        lock_sock(ssk);
@@ -640,7 +648,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
                        return NULL;
                }
 
-               mptcp_init_sock(new_mptcp_sock);
+               __mptcp_init_sock(new_mptcp_sock);
 
                msk = mptcp_sk(new_mptcp_sock);
                msk->remote_key = subflow->remote_key;
@@ -1078,7 +1086,7 @@ static struct inet_protosw mptcp_protosw = {
        .flags          = INET_PROTOSW_ICSK,
 };
 
-void __init mptcp_init(void)
+void mptcp_proto_init(void)
 {
        mptcp_prot.h.hashinfo = tcp_prot.h.hashinfo;
        mptcp_stream_ops = inet_stream_ops;
@@ -1116,7 +1124,7 @@ static struct inet_protosw mptcp_v6_protosw = {
        .flags          = INET_PROTOSW_ICSK,
 };
 
-int mptcpv6_init(void)
+int mptcp_proto_v6_init(void)
 {
        int err;
 
index 59a83eb64d375504f7a0d94f6320e42cd951f5cf..a8fad7d78565b93f3763091ae0600595beed4c3c 100644 (file)
@@ -179,6 +179,9 @@ extern const struct inet_connection_sock_af_ops ipv6_specific;
 #endif
 
 void mptcp_proto_init(void);
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+int mptcp_proto_v6_init(void);
+#endif
 
 struct mptcp_read_arg {
        struct msghdr *msg;