Skip to content

Commit

Permalink
mptcp: Handle MPTCP TCP options
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Peter Krystad authored and David S. Miller committed Jan 24, 2020
1 parent f870fa0 commit eda7acd
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 1 deletion.
18 changes: 18 additions & 0 deletions include/linux/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ struct tcp_sack_block {
#define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */
#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 {
/* PAWS/RTTM data */
int ts_recent_stamp;/* Time we stored ts_recent (for aging) */
Expand All @@ -95,6 +105,9 @@ struct tcp_options_received {
u8 num_sacks; /* Number of SACK blocks */
u16 user_mss; /* mss requested by user in ioctl */
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)
Expand All @@ -104,6 +117,11 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
#if IS_ENABLED(CONFIG_SMC)
rx_opt->smc_ok = 0;
#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
Expand Down
18 changes: 18 additions & 0 deletions include/net/mptcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define __NET_MPTCP_H

#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/types.h>

/* MPTCP sk_buff extension data */
Expand All @@ -26,10 +27,22 @@ struct mptcp_ext {
/* one byte hole */
};

struct mptcp_out_options {
#if IS_ENABLED(CONFIG_MPTCP)
u16 suboptions;
u64 sndr_key;
u64 rcvr_key;
#endif
};

#ifdef CONFIG_MPTCP

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
* newly allocated
*/
Expand Down Expand Up @@ -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,
const struct sk_buff *from)
{
Expand Down
5 changes: 5 additions & 0 deletions net/ipv4/tcp_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#include <trace/events/tcp.h>
#include <linux/jump_label_ratelimit.h>
#include <net/busy_poll.h>
#include <net/mptcp.h>

int sysctl_tcp_max_orphans __read_mostly = NR_FILE;

Expand Down Expand Up @@ -3924,6 +3925,10 @@ void tcp_parse_options(const struct net *net,
*/
break;
#endif
case TCPOPT_MPTCP:
mptcp_parse_option(ptr, opsize, opt_rx);
break;

case TCPOPT_FASTOPEN:
tcp_parse_fastopen_option(
opsize - TCPOLEN_FASTOPEN_BASE,
Expand Down
13 changes: 13 additions & 0 deletions net/ipv4/tcp_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#define pr_fmt(fmt) "TCP: " fmt

#include <net/tcp.h>
#include <net/mptcp.h>

#include <linux/compiler.h>
#include <linux/gfp.h>
Expand Down Expand Up @@ -414,6 +415,7 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
#define OPTION_WSCALE (1 << 3)
#define OPTION_FAST_OPEN_COOKIE (1 << 8)
#define OPTION_SMC (1 << 9)
#define OPTION_MPTCP (1 << 10)

static void smc_options_write(__be32 *ptr, u16 *options)
{
Expand All @@ -439,8 +441,17 @@ struct tcp_out_options {
__u8 *hash_location; /* temporary pointer, overloaded */
__u32 tsval, tsecr; /* need to include OPTION_TS */
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.
*
* Beware: Something in the Internet is very sensitive to the ordering of
Expand Down Expand Up @@ -549,6 +560,8 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
}

smc_options_write(ptr, &options);

mptcp_options_write(ptr, opts);
}

static void smc_set_option(const struct tcp_sock *tp,
Expand Down
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
mptcp-y := protocol.o options.o
97 changes: 97 additions & 0 deletions net/mptcp/options.c
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
29 changes: 29 additions & 0 deletions net/mptcp/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,35 @@
#ifndef __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 */
struct mptcp_sock {
/* inet_connection_sock must be the first member */
Expand Down

0 comments on commit eda7acd

Please sign in to comment.