Skip to content

Commit

Permalink
mptcp: new sysctl to control the activation per NS
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
matttbe authored and davem330 committed Jan 24, 2020
1 parent 5704075 commit 784325e
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 5 deletions.
2 changes: 1 addition & 1 deletion net/mptcp/Makefile
Original file line number Diff line number Diff line change
@@ -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
130 changes: 130 additions & 0 deletions net/mptcp/ctrl.c
Original file line number Diff line number Diff line change
@@ -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
16 changes: 12 additions & 4 deletions net/mptcp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
3 changes: 3 additions & 0 deletions net/mptcp/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 784325e

Please sign in to comment.