mptcp: Handle MPTCP TCP options
Add hooks to parse and format the MP_CAPABLE option. This option is handled according to MPTCP version 0 (RFC6824). MPTCP version 1 MP_CAPABLE (RFC6824bis/RFC8684) will be added later in coordination with related code changes. Co-developed-by: Matthieu Baerts <matthieu.baerts@tessares.net> Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net> Co-developed-by: Florian Westphal <fw@strlen.de> Signed-off-by: Florian Westphal <fw@strlen.de> Co-developed-by: Davide Caratti <dcaratti@redhat.com> Signed-off-by: Davide Caratti <dcaratti@redhat.com> Signed-off-by: Peter Krystad <peter.krystad@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:

committed by
David S. Miller

parent
f870fa0b57
commit
eda7acddf8
@@ -78,6 +78,16 @@ struct tcp_sack_block {
|
|||||||
#define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */
|
#define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */
|
||||||
#define TCP_DSACK_SEEN (1 << 2) /*1 = DSACK was received from peer*/
|
#define TCP_DSACK_SEEN (1 << 2) /*1 = DSACK was received from peer*/
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_MPTCP)
|
||||||
|
struct mptcp_options_received {
|
||||||
|
u64 sndr_key;
|
||||||
|
u64 rcvr_key;
|
||||||
|
u8 mp_capable : 1,
|
||||||
|
mp_join : 1,
|
||||||
|
dss : 1;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct tcp_options_received {
|
struct tcp_options_received {
|
||||||
/* PAWS/RTTM data */
|
/* PAWS/RTTM data */
|
||||||
int ts_recent_stamp;/* Time we stored ts_recent (for aging) */
|
int ts_recent_stamp;/* Time we stored ts_recent (for aging) */
|
||||||
@@ -95,6 +105,9 @@ struct tcp_options_received {
|
|||||||
u8 num_sacks; /* Number of SACK blocks */
|
u8 num_sacks; /* Number of SACK blocks */
|
||||||
u16 user_mss; /* mss requested by user in ioctl */
|
u16 user_mss; /* mss requested by user in ioctl */
|
||||||
u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
|
u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
|
||||||
|
#if IS_ENABLED(CONFIG_MPTCP)
|
||||||
|
struct mptcp_options_received mptcp;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
|
static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
|
||||||
@@ -104,6 +117,11 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
|
|||||||
#if IS_ENABLED(CONFIG_SMC)
|
#if IS_ENABLED(CONFIG_SMC)
|
||||||
rx_opt->smc_ok = 0;
|
rx_opt->smc_ok = 0;
|
||||||
#endif
|
#endif
|
||||||
|
#if IS_ENABLED(CONFIG_MPTCP)
|
||||||
|
rx_opt->mptcp.mp_capable = 0;
|
||||||
|
rx_opt->mptcp.mp_join = 0;
|
||||||
|
rx_opt->mptcp.dss = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the max number of SACKS that we'll generate and process. It's safe
|
/* This is the max number of SACKS that we'll generate and process. It's safe
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#define __NET_MPTCP_H
|
#define __NET_MPTCP_H
|
||||||
|
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/tcp.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
/* MPTCP sk_buff extension data */
|
/* MPTCP sk_buff extension data */
|
||||||
@@ -26,10 +27,22 @@ struct mptcp_ext {
|
|||||||
/* one byte hole */
|
/* one byte hole */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mptcp_out_options {
|
||||||
|
#if IS_ENABLED(CONFIG_MPTCP)
|
||||||
|
u16 suboptions;
|
||||||
|
u64 sndr_key;
|
||||||
|
u64 rcvr_key;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_MPTCP
|
#ifdef CONFIG_MPTCP
|
||||||
|
|
||||||
void mptcp_init(void);
|
void mptcp_init(void);
|
||||||
|
|
||||||
|
void mptcp_parse_option(const unsigned char *ptr, int opsize,
|
||||||
|
struct tcp_options_received *opt_rx);
|
||||||
|
void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts);
|
||||||
|
|
||||||
/* 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
|
||||||
*/
|
*/
|
||||||
@@ -76,6 +89,11 @@ static inline void mptcp_init(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void mptcp_parse_option(const unsigned char *ptr, int opsize,
|
||||||
|
struct tcp_options_received *opt_rx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@@ -79,6 +79,7 @@
|
|||||||
#include <trace/events/tcp.h>
|
#include <trace/events/tcp.h>
|
||||||
#include <linux/jump_label_ratelimit.h>
|
#include <linux/jump_label_ratelimit.h>
|
||||||
#include <net/busy_poll.h>
|
#include <net/busy_poll.h>
|
||||||
|
#include <net/mptcp.h>
|
||||||
|
|
||||||
int sysctl_tcp_max_orphans __read_mostly = NR_FILE;
|
int sysctl_tcp_max_orphans __read_mostly = NR_FILE;
|
||||||
|
|
||||||
@@ -3924,6 +3925,10 @@ void tcp_parse_options(const struct net *net,
|
|||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case TCPOPT_MPTCP:
|
||||||
|
mptcp_parse_option(ptr, opsize, opt_rx);
|
||||||
|
break;
|
||||||
|
|
||||||
case TCPOPT_FASTOPEN:
|
case TCPOPT_FASTOPEN:
|
||||||
tcp_parse_fastopen_option(
|
tcp_parse_fastopen_option(
|
||||||
opsize - TCPOLEN_FASTOPEN_BASE,
|
opsize - TCPOLEN_FASTOPEN_BASE,
|
||||||
|
@@ -38,6 +38,7 @@
|
|||||||
#define pr_fmt(fmt) "TCP: " fmt
|
#define pr_fmt(fmt) "TCP: " fmt
|
||||||
|
|
||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
#include <net/mptcp.h>
|
||||||
|
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
@@ -414,6 +415,7 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
|
|||||||
#define OPTION_WSCALE (1 << 3)
|
#define OPTION_WSCALE (1 << 3)
|
||||||
#define OPTION_FAST_OPEN_COOKIE (1 << 8)
|
#define OPTION_FAST_OPEN_COOKIE (1 << 8)
|
||||||
#define OPTION_SMC (1 << 9)
|
#define OPTION_SMC (1 << 9)
|
||||||
|
#define OPTION_MPTCP (1 << 10)
|
||||||
|
|
||||||
static void smc_options_write(__be32 *ptr, u16 *options)
|
static void smc_options_write(__be32 *ptr, u16 *options)
|
||||||
{
|
{
|
||||||
@@ -439,8 +441,17 @@ struct tcp_out_options {
|
|||||||
__u8 *hash_location; /* temporary pointer, overloaded */
|
__u8 *hash_location; /* temporary pointer, overloaded */
|
||||||
__u32 tsval, tsecr; /* need to include OPTION_TS */
|
__u32 tsval, tsecr; /* need to include OPTION_TS */
|
||||||
struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
|
struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
|
||||||
|
struct mptcp_out_options mptcp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void mptcp_options_write(__be32 *ptr, struct tcp_out_options *opts)
|
||||||
|
{
|
||||||
|
#if IS_ENABLED(CONFIG_MPTCP)
|
||||||
|
if (unlikely(OPTION_MPTCP & opts->options))
|
||||||
|
mptcp_write_options(ptr, &opts->mptcp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Write previously computed TCP options to the packet.
|
/* Write previously computed TCP options to the packet.
|
||||||
*
|
*
|
||||||
* Beware: Something in the Internet is very sensitive to the ordering of
|
* Beware: Something in the Internet is very sensitive to the ordering of
|
||||||
@@ -549,6 +560,8 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
smc_options_write(ptr, &options);
|
smc_options_write(ptr, &options);
|
||||||
|
|
||||||
|
mptcp_options_write(ptr, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smc_set_option(const struct tcp_sock *tp,
|
static void smc_set_option(const struct tcp_sock *tp,
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
obj-$(CONFIG_MPTCP) += mptcp.o
|
obj-$(CONFIG_MPTCP) += mptcp.o
|
||||||
|
|
||||||
mptcp-y := protocol.o
|
mptcp-y := protocol.o options.o
|
||||||
|
97
net/mptcp/options.c
Normal file
97
net/mptcp/options.c
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/* Multipath TCP
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 - 2019, Intel Corporation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <net/tcp.h>
|
||||||
|
#include <net/mptcp.h>
|
||||||
|
#include "protocol.h"
|
||||||
|
|
||||||
|
void mptcp_parse_option(const unsigned char *ptr, int opsize,
|
||||||
|
struct tcp_options_received *opt_rx)
|
||||||
|
{
|
||||||
|
struct mptcp_options_received *mp_opt = &opt_rx->mptcp;
|
||||||
|
u8 subtype = *ptr >> 4;
|
||||||
|
u8 version;
|
||||||
|
u8 flags;
|
||||||
|
|
||||||
|
switch (subtype) {
|
||||||
|
case MPTCPOPT_MP_CAPABLE:
|
||||||
|
if (opsize != TCPOLEN_MPTCP_MPC_SYN &&
|
||||||
|
opsize != TCPOLEN_MPTCP_MPC_ACK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
version = *ptr++ & MPTCP_VERSION_MASK;
|
||||||
|
if (version != MPTCP_SUPPORTED_VERSION)
|
||||||
|
break;
|
||||||
|
|
||||||
|
flags = *ptr++;
|
||||||
|
if (!((flags & MPTCP_CAP_FLAG_MASK) == MPTCP_CAP_HMAC_SHA1) ||
|
||||||
|
(flags & MPTCP_CAP_EXTENSIBILITY))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* RFC 6824, Section 3.1:
|
||||||
|
* "For the Checksum Required bit (labeled "A"), if either
|
||||||
|
* host requires the use of checksums, checksums MUST be used.
|
||||||
|
* In other words, the only way for checksums not to be used
|
||||||
|
* is if both hosts in their SYNs set A=0."
|
||||||
|
*
|
||||||
|
* Section 3.3.0:
|
||||||
|
* "If a checksum is not present when its use has been
|
||||||
|
* negotiated, the receiver MUST close the subflow with a RST as
|
||||||
|
* it is considered broken."
|
||||||
|
*
|
||||||
|
* We don't implement DSS checksum - fall back to TCP.
|
||||||
|
*/
|
||||||
|
if (flags & MPTCP_CAP_CHECKSUM_REQD)
|
||||||
|
break;
|
||||||
|
|
||||||
|
mp_opt->mp_capable = 1;
|
||||||
|
mp_opt->sndr_key = get_unaligned_be64(ptr);
|
||||||
|
ptr += 8;
|
||||||
|
|
||||||
|
if (opsize == TCPOLEN_MPTCP_MPC_ACK) {
|
||||||
|
mp_opt->rcvr_key = get_unaligned_be64(ptr);
|
||||||
|
ptr += 8;
|
||||||
|
pr_debug("MP_CAPABLE sndr=%llu, rcvr=%llu",
|
||||||
|
mp_opt->sndr_key, mp_opt->rcvr_key);
|
||||||
|
} else {
|
||||||
|
pr_debug("MP_CAPABLE sndr=%llu", mp_opt->sndr_key);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MPTCPOPT_DSS:
|
||||||
|
pr_debug("DSS");
|
||||||
|
mp_opt->dss = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
|
||||||
|
{
|
||||||
|
if ((OPTION_MPTCP_MPC_SYN |
|
||||||
|
OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
|
||||||
|
u8 len;
|
||||||
|
|
||||||
|
if (OPTION_MPTCP_MPC_SYN & opts->suboptions)
|
||||||
|
len = TCPOLEN_MPTCP_MPC_SYN;
|
||||||
|
else
|
||||||
|
len = TCPOLEN_MPTCP_MPC_ACK;
|
||||||
|
|
||||||
|
*ptr++ = htonl((TCPOPT_MPTCP << 24) | (len << 16) |
|
||||||
|
(MPTCPOPT_MP_CAPABLE << 12) |
|
||||||
|
(MPTCP_SUPPORTED_VERSION << 8) |
|
||||||
|
MPTCP_CAP_HMAC_SHA1);
|
||||||
|
put_unaligned_be64(opts->sndr_key, ptr);
|
||||||
|
ptr += 2;
|
||||||
|
if (OPTION_MPTCP_MPC_ACK & opts->suboptions) {
|
||||||
|
put_unaligned_be64(opts->rcvr_key, ptr);
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -7,6 +7,35 @@
|
|||||||
#ifndef __MPTCP_PROTOCOL_H
|
#ifndef __MPTCP_PROTOCOL_H
|
||||||
#define __MPTCP_PROTOCOL_H
|
#define __MPTCP_PROTOCOL_H
|
||||||
|
|
||||||
|
#define MPTCP_SUPPORTED_VERSION 0
|
||||||
|
|
||||||
|
/* MPTCP option bits */
|
||||||
|
#define OPTION_MPTCP_MPC_SYN BIT(0)
|
||||||
|
#define OPTION_MPTCP_MPC_SYNACK BIT(1)
|
||||||
|
#define OPTION_MPTCP_MPC_ACK BIT(2)
|
||||||
|
|
||||||
|
/* MPTCP option subtypes */
|
||||||
|
#define MPTCPOPT_MP_CAPABLE 0
|
||||||
|
#define MPTCPOPT_MP_JOIN 1
|
||||||
|
#define MPTCPOPT_DSS 2
|
||||||
|
#define MPTCPOPT_ADD_ADDR 3
|
||||||
|
#define MPTCPOPT_RM_ADDR 4
|
||||||
|
#define MPTCPOPT_MP_PRIO 5
|
||||||
|
#define MPTCPOPT_MP_FAIL 6
|
||||||
|
#define MPTCPOPT_MP_FASTCLOSE 7
|
||||||
|
|
||||||
|
/* MPTCP suboption lengths */
|
||||||
|
#define TCPOLEN_MPTCP_MPC_SYN 12
|
||||||
|
#define TCPOLEN_MPTCP_MPC_SYNACK 12
|
||||||
|
#define TCPOLEN_MPTCP_MPC_ACK 20
|
||||||
|
|
||||||
|
/* MPTCP MP_CAPABLE flags */
|
||||||
|
#define MPTCP_VERSION_MASK (0x0F)
|
||||||
|
#define MPTCP_CAP_CHECKSUM_REQD BIT(7)
|
||||||
|
#define MPTCP_CAP_EXTENSIBILITY BIT(6)
|
||||||
|
#define MPTCP_CAP_HMAC_SHA1 BIT(0)
|
||||||
|
#define MPTCP_CAP_FLAG_MASK (0x3F)
|
||||||
|
|
||||||
/* MPTCP connection sock */
|
/* MPTCP connection sock */
|
||||||
struct mptcp_sock {
|
struct mptcp_sock {
|
||||||
/* inet_connection_sock must be the first member */
|
/* inet_connection_sock must be the first member */
|
||||||
|
Reference in New Issue
Block a user