Commit a29b56c4 authored by David S. Miller's avatar David S. Miller

Merge branch 'mptcp-Improve-DATA_FIN-transmission'

Mat Martineau says:

====================
mptcp: Improve DATA_FIN transmission

MPTCP's DATA_FIN flag is sent in a DSS option when closing the
MPTCP-level connection. This patch series prepares for correct DATA_FIN
handling across multiple subflows (where individual subflows may
disconnect without closing the entire MPTCP connection) by changing the
way the MPTCP-level socket requests a DATA_FIN on a subflow and
propagates the necessary data for the TCP option.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0a303214 6d37a0b8
...@@ -304,21 +304,22 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb, ...@@ -304,21 +304,22 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,
static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow, static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
struct mptcp_ext *ext) struct mptcp_ext *ext)
{ {
ext->data_fin = 1;
if (!ext->use_map) { if (!ext->use_map) {
/* RFC6824 requires a DSS mapping with specific values /* RFC6824 requires a DSS mapping with specific values
* if DATA_FIN is set but no data payload is mapped * if DATA_FIN is set but no data payload is mapped
*/ */
ext->data_fin = 1;
ext->use_map = 1; ext->use_map = 1;
ext->dsn64 = 1; ext->dsn64 = 1;
ext->data_seq = mptcp_sk(subflow->conn)->write_seq; ext->data_seq = subflow->data_fin_tx_seq;
ext->subflow_seq = 0; ext->subflow_seq = 0;
ext->data_len = 1; ext->data_len = 1;
} else { } else if (ext->data_seq + ext->data_len == subflow->data_fin_tx_seq) {
/* If there's an existing DSS mapping, DATA_FIN consumes /* If there's an existing DSS mapping and it is the
* 1 additional byte of mapping space. * final mapping, DATA_FIN consumes 1 additional byte of
* mapping space.
*/ */
ext->data_fin = 1;
ext->data_len++; ext->data_len++;
} }
} }
...@@ -354,8 +355,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb, ...@@ -354,8 +355,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
if (mpext) if (mpext)
opts->ext_copy = *mpext; opts->ext_copy = *mpext;
if (skb && tcp_fin && if (skb && tcp_fin && subflow->data_fin_tx_enable)
subflow->conn->sk_state != TCP_ESTABLISHED)
mptcp_write_data_fin(subflow, &opts->ext_copy); mptcp_write_data_fin(subflow, &opts->ext_copy);
ret = true; ret = true;
} }
......
...@@ -419,6 +419,15 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -419,6 +419,15 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return -EOPNOTSUPP; return -EOPNOTSUPP;
lock_sock(sk); lock_sock(sk);
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
ret = sk_stream_wait_connect(sk, &timeo);
if (ret)
goto out;
}
ssock = __mptcp_tcp_fallback(msk); ssock = __mptcp_tcp_fallback(msk);
if (unlikely(ssock)) { if (unlikely(ssock)) {
fallback: fallback:
...@@ -427,8 +436,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -427,8 +436,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return ret >= 0 ? ret + copied : (copied ? copied : ret); return ret >= 0 ? ret + copied : (copied ? copied : ret);
} }
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
ssk = mptcp_subflow_get(msk); ssk = mptcp_subflow_get(msk);
if (!ssk) { if (!ssk) {
release_sock(sk); release_sock(sk);
...@@ -460,6 +467,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -460,6 +467,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
ssk_check_wmem(msk, ssk); ssk_check_wmem(msk, ssk);
release_sock(ssk); release_sock(ssk);
out:
release_sock(sk); release_sock(sk);
return ret; return ret;
} }
...@@ -712,7 +720,8 @@ static void mptcp_cancel_work(struct sock *sk) ...@@ -712,7 +720,8 @@ static void mptcp_cancel_work(struct sock *sk)
sock_put(sk); sock_put(sk);
} }
static void mptcp_subflow_shutdown(struct sock *ssk, int how) static void mptcp_subflow_shutdown(struct sock *ssk, int how,
bool data_fin_tx_enable, u64 data_fin_tx_seq)
{ {
lock_sock(ssk); lock_sock(ssk);
...@@ -725,6 +734,14 @@ static void mptcp_subflow_shutdown(struct sock *ssk, int how) ...@@ -725,6 +734,14 @@ static void mptcp_subflow_shutdown(struct sock *ssk, int how)
tcp_disconnect(ssk, O_NONBLOCK); tcp_disconnect(ssk, O_NONBLOCK);
break; break;
default: default:
if (data_fin_tx_enable) {
struct mptcp_subflow_context *subflow;
subflow = mptcp_subflow_ctx(ssk);
subflow->data_fin_tx_seq = data_fin_tx_seq;
subflow->data_fin_tx_enable = 1;
}
ssk->sk_shutdown |= how; ssk->sk_shutdown |= how;
tcp_shutdown(ssk, how); tcp_shutdown(ssk, how);
break; break;
...@@ -741,6 +758,7 @@ static void mptcp_close(struct sock *sk, long timeout) ...@@ -741,6 +758,7 @@ static void mptcp_close(struct sock *sk, long timeout)
struct mptcp_subflow_context *subflow, *tmp; struct mptcp_subflow_context *subflow, *tmp;
struct mptcp_sock *msk = mptcp_sk(sk); struct mptcp_sock *msk = mptcp_sk(sk);
LIST_HEAD(conn_list); LIST_HEAD(conn_list);
u64 data_fin_tx_seq;
lock_sock(sk); lock_sock(sk);
...@@ -749,11 +767,15 @@ static void mptcp_close(struct sock *sk, long timeout) ...@@ -749,11 +767,15 @@ static void mptcp_close(struct sock *sk, long timeout)
list_splice_init(&msk->conn_list, &conn_list); list_splice_init(&msk->conn_list, &conn_list);
data_fin_tx_seq = msk->write_seq;
release_sock(sk); release_sock(sk);
list_for_each_entry_safe(subflow, tmp, &conn_list, node) { list_for_each_entry_safe(subflow, tmp, &conn_list, node) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow); struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
subflow->data_fin_tx_seq = data_fin_tx_seq;
subflow->data_fin_tx_enable = 1;
__mptcp_close_ssk(sk, ssk, subflow, timeout); __mptcp_close_ssk(sk, ssk, subflow, timeout);
} }
...@@ -846,7 +868,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err, ...@@ -846,7 +868,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
*err = -ENOBUFS; *err = -ENOBUFS;
local_bh_enable(); local_bh_enable();
release_sock(sk); release_sock(sk);
mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1); mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1, 0, 0);
tcp_close(newsk, 0); tcp_close(newsk, 0);
return NULL; return NULL;
} }
...@@ -1301,7 +1323,7 @@ static int mptcp_shutdown(struct socket *sock, int how) ...@@ -1301,7 +1323,7 @@ static int mptcp_shutdown(struct socket *sock, int how)
mptcp_for_each_subflow(msk, subflow) { mptcp_for_each_subflow(msk, subflow) {
struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow); struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow);
mptcp_subflow_shutdown(tcp_sk, how); mptcp_subflow_shutdown(tcp_sk, how, 1, msk->write_seq);
} }
out_unlock: out_unlock:
......
...@@ -125,7 +125,9 @@ struct mptcp_subflow_context { ...@@ -125,7 +125,9 @@ struct mptcp_subflow_context {
mpc_map : 1, mpc_map : 1,
data_avail : 1, data_avail : 1,
rx_eof : 1, rx_eof : 1,
data_fin_tx_enable : 1,
can_ack : 1; /* only after processing the remote a key */ can_ack : 1; /* only after processing the remote a key */
u64 data_fin_tx_seq;
struct sock *tcp_sock; /* tcp sk backpointer */ struct sock *tcp_sock; /* tcp sk backpointer */
struct sock *conn; /* parent mptcp_sock */ struct sock *conn; /* parent mptcp_sock */
......
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