mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-12 15:44:01 +08:00
6d0060f600
Per-packet metadata required to write the MPTCP DSS option is written to the skb_ext area. One write to the socket may contain more than one packet of data, which is copied to page fragments and mapped in to MPTCP DSS segments with size determined by the available page fragments and the maximum mapping length allowed by the MPTCP specification. If do_tcp_sendpages() splits a DSS segment in to multiple skbs, that's ok - the later skbs can either have duplicated DSS mapping information or none at all, and the receiver can handle that. The current implementation uses the subflow frag cache and tcp sendpages to avoid excessive code duplication. More work is required to ensure that it works correctly under memory pressure and to support MPTCP-level retransmissions. The MPTCP DSS checksum is not yet implemented. Co-developed-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Co-developed-by: Peter Krystad <peter.krystad@linux.intel.com> Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com> Co-developed-by: Florian Westphal <fw@strlen.de> Signed-off-by: Florian Westphal <fw@strlen.de> 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>
178 lines
3.9 KiB
C
178 lines
3.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Multipath TCP
|
|
*
|
|
* Copyright (c) 2017 - 2019, Intel Corporation.
|
|
*/
|
|
|
|
#ifndef __NET_MPTCP_H
|
|
#define __NET_MPTCP_H
|
|
|
|
#include <linux/skbuff.h>
|
|
#include <linux/tcp.h>
|
|
#include <linux/types.h>
|
|
|
|
/* MPTCP sk_buff extension data */
|
|
struct mptcp_ext {
|
|
u64 data_ack;
|
|
u64 data_seq;
|
|
u32 subflow_seq;
|
|
u16 data_len;
|
|
u8 use_map:1,
|
|
dsn64:1,
|
|
data_fin:1,
|
|
use_ack:1,
|
|
ack64:1,
|
|
__unused:3;
|
|
/* one byte hole */
|
|
};
|
|
|
|
struct mptcp_out_options {
|
|
#if IS_ENABLED(CONFIG_MPTCP)
|
|
u16 suboptions;
|
|
u64 sndr_key;
|
|
u64 rcvr_key;
|
|
struct mptcp_ext ext_copy;
|
|
#endif
|
|
};
|
|
|
|
#ifdef CONFIG_MPTCP
|
|
|
|
void mptcp_init(void);
|
|
|
|
static inline bool sk_is_mptcp(const struct sock *sk)
|
|
{
|
|
return tcp_sk(sk)->is_mptcp;
|
|
}
|
|
|
|
static inline bool rsk_is_mptcp(const struct request_sock *req)
|
|
{
|
|
return tcp_rsk(req)->is_mptcp;
|
|
}
|
|
|
|
void mptcp_parse_option(const unsigned char *ptr, int opsize,
|
|
struct tcp_options_received *opt_rx);
|
|
bool mptcp_syn_options(struct sock *sk, unsigned int *size,
|
|
struct mptcp_out_options *opts);
|
|
void mptcp_rcv_synsent(struct sock *sk);
|
|
bool mptcp_synack_options(const struct request_sock *req, unsigned int *size,
|
|
struct mptcp_out_options *opts);
|
|
bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
|
|
unsigned int *size, unsigned int remaining,
|
|
struct mptcp_out_options *opts);
|
|
|
|
void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts);
|
|
|
|
/* move the skb extension owership, with the assumption that 'to' is
|
|
* newly allocated
|
|
*/
|
|
static inline void mptcp_skb_ext_move(struct sk_buff *to,
|
|
struct sk_buff *from)
|
|
{
|
|
if (!skb_ext_exist(from, SKB_EXT_MPTCP))
|
|
return;
|
|
|
|
if (WARN_ON_ONCE(to->active_extensions))
|
|
skb_ext_put(to);
|
|
|
|
to->active_extensions = from->active_extensions;
|
|
to->extensions = from->extensions;
|
|
from->active_extensions = 0;
|
|
}
|
|
|
|
static inline bool mptcp_ext_matches(const struct mptcp_ext *to_ext,
|
|
const struct mptcp_ext *from_ext)
|
|
{
|
|
/* MPTCP always clears the ext when adding it to the skb, so
|
|
* holes do not bother us here
|
|
*/
|
|
return !from_ext ||
|
|
(to_ext && from_ext &&
|
|
!memcmp(from_ext, to_ext, sizeof(struct mptcp_ext)));
|
|
}
|
|
|
|
/* check if skbs can be collapsed.
|
|
* MPTCP collapse is allowed if neither @to or @from carry an mptcp data
|
|
* mapping, or if the extension of @to is the same as @from.
|
|
* Collapsing is not possible if @to lacks an extension, but @from carries one.
|
|
*/
|
|
static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
|
|
const struct sk_buff *from)
|
|
{
|
|
return mptcp_ext_matches(skb_ext_find(to, SKB_EXT_MPTCP),
|
|
skb_ext_find(from, SKB_EXT_MPTCP));
|
|
}
|
|
|
|
#else
|
|
|
|
static inline void mptcp_init(void)
|
|
{
|
|
}
|
|
|
|
static inline bool sk_is_mptcp(const struct sock *sk)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline bool rsk_is_mptcp(const struct request_sock *req)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline void mptcp_parse_option(const unsigned char *ptr, int opsize,
|
|
struct tcp_options_received *opt_rx)
|
|
{
|
|
}
|
|
|
|
static inline bool mptcp_syn_options(struct sock *sk, unsigned int *size,
|
|
struct mptcp_out_options *opts)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline void mptcp_rcv_synsent(struct sock *sk)
|
|
{
|
|
}
|
|
|
|
static inline bool mptcp_synack_options(const struct request_sock *req,
|
|
unsigned int *size,
|
|
struct mptcp_out_options *opts)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline bool mptcp_established_options(struct sock *sk,
|
|
struct sk_buff *skb,
|
|
unsigned int *size,
|
|
unsigned int remaining,
|
|
struct mptcp_out_options *opts)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline void mptcp_skb_ext_move(struct sk_buff *to,
|
|
const struct sk_buff *from)
|
|
{
|
|
}
|
|
|
|
static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
|
|
const struct sk_buff *from)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
#endif /* CONFIG_MPTCP */
|
|
|
|
void mptcp_handle_ipv6_mapped(struct sock *sk, bool mapped);
|
|
|
|
#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 */
|