Implements the infrastructure for MPTCP sockets.

MPTCP sockets open one in-kernel TCP socket per subflow. These subflow
sockets are only managed by the MPTCP socket that owns them and are not
visible from userspace. This commit allows a userspace program to open
an MPTCP socket with:

  sock = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP);

The resulting socket is simply a wrapper around a single regular TCP
socket, without any of the MPTCP protocol implemented over the wire.

Co-developed-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Florian Westphal <fw@strlen.de>
Co-developed-by: Peter Krystad <peter.krystad@linux.intel.com>
Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com>
Co-developed-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Co-developed-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: Christoph Paasch <cpaasch@apple.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Mat Martineau 2020-01-21 16:56:15 -08:00 коммит произвёл David S. Miller
Родитель 23f4eacdd2
Коммит f870fa0b57
10 изменённых файлов: 212 добавлений и 0 удалений

Просмотреть файл

@ -11583,6 +11583,7 @@ W: https://github.com/multipath-tcp/mptcp_net-next/wiki
B: https://github.com/multipath-tcp/mptcp_net-next/issues B: https://github.com/multipath-tcp/mptcp_net-next/issues
S: Maintained S: Maintained
F: include/net/mptcp.h F: include/net/mptcp.h
F: net/mptcp/
NETWORKING [TCP] NETWORKING [TCP]
M: Eric Dumazet <edumazet@google.com> M: Eric Dumazet <edumazet@google.com>

Просмотреть файл

@ -28,6 +28,8 @@ struct mptcp_ext {
#ifdef CONFIG_MPTCP #ifdef CONFIG_MPTCP
void mptcp_init(void);
/* move the skb extension owership, with the assumption that 'to' is /* move the skb extension owership, with the assumption that 'to' is
* newly allocated * newly allocated
*/ */
@ -70,6 +72,10 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
#else #else
static inline void mptcp_init(void)
{
}
static inline void mptcp_skb_ext_move(struct sk_buff *to, static inline void mptcp_skb_ext_move(struct sk_buff *to,
const struct sk_buff *from) const struct sk_buff *from)
{ {
@ -82,4 +88,14 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
} }
#endif /* CONFIG_MPTCP */ #endif /* CONFIG_MPTCP */
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
int mptcpv6_init(void);
#elif IS_ENABLED(CONFIG_IPV6)
static inline int mptcpv6_init(void)
{
return 0;
}
#endif
#endif /* __NET_MPTCP_H */ #endif /* __NET_MPTCP_H */

Просмотреть файл

@ -91,6 +91,7 @@ if INET
source "net/ipv4/Kconfig" source "net/ipv4/Kconfig"
source "net/ipv6/Kconfig" source "net/ipv6/Kconfig"
source "net/netlabel/Kconfig" source "net/netlabel/Kconfig"
source "net/mptcp/Kconfig"
endif # if INET endif # if INET

Просмотреть файл

@ -87,3 +87,4 @@ endif
obj-$(CONFIG_QRTR) += qrtr/ obj-$(CONFIG_QRTR) += qrtr/
obj-$(CONFIG_NET_NCSI) += ncsi/ obj-$(CONFIG_NET_NCSI) += ncsi/
obj-$(CONFIG_XDP_SOCKETS) += xdp/ obj-$(CONFIG_XDP_SOCKETS) += xdp/
obj-$(CONFIG_MPTCP) += mptcp/

Просмотреть файл

@ -271,6 +271,7 @@
#include <net/icmp.h> #include <net/icmp.h>
#include <net/inet_common.h> #include <net/inet_common.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/mptcp.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/sock.h> #include <net/sock.h>
@ -4021,4 +4022,5 @@ void __init tcp_init(void)
tcp_metrics_init(); tcp_metrics_init();
BUG_ON(tcp_register_congestion_control(&tcp_reno) != 0); BUG_ON(tcp_register_congestion_control(&tcp_reno) != 0);
tcp_tasklet_init(); tcp_tasklet_init();
mptcp_init();
} }

Просмотреть файл

@ -2163,9 +2163,16 @@ int __init tcpv6_init(void)
ret = register_pernet_subsys(&tcpv6_net_ops); ret = register_pernet_subsys(&tcpv6_net_ops);
if (ret) if (ret)
goto out_tcpv6_protosw; goto out_tcpv6_protosw;
ret = mptcpv6_init();
if (ret)
goto out_tcpv6_pernet_subsys;
out: out:
return ret; return ret;
out_tcpv6_pernet_subsys:
unregister_pernet_subsys(&tcpv6_net_ops);
out_tcpv6_protosw: out_tcpv6_protosw:
inet6_unregister_protosw(&tcpv6_protosw); inet6_unregister_protosw(&tcpv6_protosw);
out_tcpv6_protocol: out_tcpv6_protocol:

16
net/mptcp/Kconfig Normal file
Просмотреть файл

@ -0,0 +1,16 @@
config MPTCP
bool "MPTCP: Multipath TCP"
depends on INET
select SKB_EXTENSIONS
help
Multipath TCP (MPTCP) connections send and receive data over multiple
subflows in order to utilize multiple network paths. Each subflow
uses the TCP protocol, and TCP options carry header information for
MPTCP.
config MPTCP_IPV6
bool "MPTCP: IPv6 support for Multipath TCP"
depends on MPTCP
select IPV6
default y

4
net/mptcp/Makefile Normal file
Просмотреть файл

@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_MPTCP) += mptcp.o
mptcp-y := protocol.o

142
net/mptcp/protocol.c Normal file
Просмотреть файл

@ -0,0 +1,142 @@
// SPDX-License-Identifier: GPL-2.0
/* Multipath TCP
*
* Copyright (c) 2017 - 2019, Intel Corporation.
*/
#define pr_fmt(fmt) "MPTCP: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <net/sock.h>
#include <net/inet_common.h>
#include <net/inet_hashtables.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/mptcp.h>
#include "protocol.h"
static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct socket *subflow = msk->subflow;
if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL))
return -EOPNOTSUPP;
return sock_sendmsg(subflow, msg);
}
static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int nonblock, int flags, int *addr_len)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct socket *subflow = msk->subflow;
if (msg->msg_flags & ~(MSG_WAITALL | MSG_DONTWAIT))
return -EOPNOTSUPP;
return sock_recvmsg(subflow, msg, flags);
}
static int mptcp_init_sock(struct sock *sk)
{
return 0;
}
static void mptcp_close(struct sock *sk, long timeout)
{
struct mptcp_sock *msk = mptcp_sk(sk);
inet_sk_state_store(sk, TCP_CLOSE);
if (msk->subflow) {
pr_debug("subflow=%p", msk->subflow->sk);
sock_release(msk->subflow);
}
sock_orphan(sk);
sock_put(sk);
}
static int mptcp_connect(struct sock *sk, struct sockaddr *saddr, int len)
{
struct mptcp_sock *msk = mptcp_sk(sk);
int err;
saddr->sa_family = AF_INET;
pr_debug("msk=%p, subflow=%p", msk, msk->subflow->sk);
err = kernel_connect(msk->subflow, saddr, len, 0);
sk->sk_state = TCP_ESTABLISHED;
return err;
}
static struct proto mptcp_prot = {
.name = "MPTCP",
.owner = THIS_MODULE,
.init = mptcp_init_sock,
.close = mptcp_close,
.accept = inet_csk_accept,
.connect = mptcp_connect,
.shutdown = tcp_shutdown,
.sendmsg = mptcp_sendmsg,
.recvmsg = mptcp_recvmsg,
.hash = inet_hash,
.unhash = inet_unhash,
.get_port = inet_csk_get_port,
.obj_size = sizeof(struct mptcp_sock),
.no_autobind = true,
};
static struct inet_protosw mptcp_protosw = {
.type = SOCK_STREAM,
.protocol = IPPROTO_MPTCP,
.prot = &mptcp_prot,
.ops = &inet_stream_ops,
};
void __init mptcp_init(void)
{
if (proto_register(&mptcp_prot, 1) != 0)
panic("Failed to register MPTCP proto.\n");
inet_register_protosw(&mptcp_protosw);
}
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
static struct proto mptcp_v6_prot;
static struct inet_protosw mptcp_v6_protosw = {
.type = SOCK_STREAM,
.protocol = IPPROTO_MPTCP,
.prot = &mptcp_v6_prot,
.ops = &inet6_stream_ops,
.flags = INET_PROTOSW_ICSK,
};
int mptcpv6_init(void)
{
int err;
mptcp_v6_prot = mptcp_prot;
strcpy(mptcp_v6_prot.name, "MPTCPv6");
mptcp_v6_prot.slab = NULL;
mptcp_v6_prot.obj_size = sizeof(struct mptcp_sock) +
sizeof(struct ipv6_pinfo);
err = proto_register(&mptcp_v6_prot, 1);
if (err)
return err;
err = inet6_register_protosw(&mptcp_v6_protosw);
if (err)
proto_unregister(&mptcp_v6_prot);
return err;
}
#endif

22
net/mptcp/protocol.h Normal file
Просмотреть файл

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Multipath TCP
*
* Copyright (c) 2017 - 2019, Intel Corporation.
*/
#ifndef __MPTCP_PROTOCOL_H
#define __MPTCP_PROTOCOL_H
/* MPTCP connection sock */
struct mptcp_sock {
/* inet_connection_sock must be the first member */
struct inet_connection_sock sk;
struct socket *subflow; /* outgoing connect/listener/!mp_capable */
};
static inline struct mptcp_sock *mptcp_sk(const struct sock *sk)
{
return (struct mptcp_sock *)sk;
}
#endif /* __MPTCP_PROTOCOL_H */