mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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: 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:
		
							parent
							
								
									23f4eacdd2
								
							
						
					
					
						commit
						f870fa0b57
					
				
					 10 changed files with 212 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -11583,6 +11583,7 @@ W:	https://github.com/multipath-tcp/mptcp_net-next/wiki
 | 
			
		|||
B:	https://github.com/multipath-tcp/mptcp_net-next/issues
 | 
			
		||||
S:	Maintained
 | 
			
		||||
F:	include/net/mptcp.h
 | 
			
		||||
F:	net/mptcp/
 | 
			
		||||
 | 
			
		||||
NETWORKING [TCP]
 | 
			
		||||
M:	Eric Dumazet <edumazet@google.com>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,8 @@ struct mptcp_ext {
 | 
			
		|||
 | 
			
		||||
#ifdef CONFIG_MPTCP
 | 
			
		||||
 | 
			
		||||
void mptcp_init(void);
 | 
			
		||||
 | 
			
		||||
/* move the skb extension owership, with the assumption that 'to' is
 | 
			
		||||
 * newly allocated
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -70,6 +72,10 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
 | 
			
		|||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
static inline void mptcp_init(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void mptcp_skb_ext_move(struct sk_buff *to,
 | 
			
		||||
				      const struct sk_buff *from)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -82,4 +88,14 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
#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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,6 +91,7 @@ if INET
 | 
			
		|||
source "net/ipv4/Kconfig"
 | 
			
		||||
source "net/ipv6/Kconfig"
 | 
			
		||||
source "net/netlabel/Kconfig"
 | 
			
		||||
source "net/mptcp/Kconfig"
 | 
			
		||||
 | 
			
		||||
endif # if INET
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,3 +87,4 @@ endif
 | 
			
		|||
obj-$(CONFIG_QRTR)		+= qrtr/
 | 
			
		||||
obj-$(CONFIG_NET_NCSI)		+= ncsi/
 | 
			
		||||
obj-$(CONFIG_XDP_SOCKETS)	+= xdp/
 | 
			
		||||
obj-$(CONFIG_MPTCP)		+= mptcp/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -271,6 +271,7 @@
 | 
			
		|||
#include <net/icmp.h>
 | 
			
		||||
#include <net/inet_common.h>
 | 
			
		||||
#include <net/tcp.h>
 | 
			
		||||
#include <net/mptcp.h>
 | 
			
		||||
#include <net/xfrm.h>
 | 
			
		||||
#include <net/ip.h>
 | 
			
		||||
#include <net/sock.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -4021,4 +4022,5 @@ void __init tcp_init(void)
 | 
			
		|||
	tcp_metrics_init();
 | 
			
		||||
	BUG_ON(tcp_register_congestion_control(&tcp_reno) != 0);
 | 
			
		||||
	tcp_tasklet_init();
 | 
			
		||||
	mptcp_init();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2163,9 +2163,16 @@ int __init tcpv6_init(void)
 | 
			
		|||
	ret = register_pernet_subsys(&tcpv6_net_ops);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out_tcpv6_protosw;
 | 
			
		||||
 | 
			
		||||
	ret = mptcpv6_init();
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out_tcpv6_pernet_subsys;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
out_tcpv6_pernet_subsys:
 | 
			
		||||
	unregister_pernet_subsys(&tcpv6_net_ops);
 | 
			
		||||
out_tcpv6_protosw:
 | 
			
		||||
	inet6_unregister_protosw(&tcpv6_protosw);
 | 
			
		||||
out_tcpv6_protocol:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								net/mptcp/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										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 */
 | 
			
		||||
		Loading…
	
		Reference in a new issue