Commit f870fa0b authored by Mat Martineau's avatar Mat Martineau Committed by David S. Miller

mptcp: Add MPTCP socket stubs

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: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Co-developed-by: default avatarPeter Krystad <peter.krystad@linux.intel.com>
Signed-off-by: default avatarPeter Krystad <peter.krystad@linux.intel.com>
Co-developed-by: default avatarMatthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: default avatarMatthieu Baerts <matthieu.baerts@tessares.net>
Co-developed-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: default avatarChristoph Paasch <cpaasch@apple.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 23f4eacd
...@@ -11583,6 +11583,7 @@ W: https://github.com/multipath-tcp/mptcp_net-next/wiki ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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 ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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:
......
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
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_MPTCP) += mptcp.o
mptcp-y := protocol.o
// 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
/* 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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment