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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
a29b56c451
|
@ -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,
|
||||
struct mptcp_ext *ext)
|
||||
{
|
||||
ext->data_fin = 1;
|
||||
|
||||
if (!ext->use_map) {
|
||||
/* RFC6824 requires a DSS mapping with specific values
|
||||
* if DATA_FIN is set but no data payload is mapped
|
||||
*/
|
||||
ext->data_fin = 1;
|
||||
ext->use_map = 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->data_len = 1;
|
||||
} else {
|
||||
/* If there's an existing DSS mapping, DATA_FIN consumes
|
||||
* 1 additional byte of mapping space.
|
||||
} else if (ext->data_seq + ext->data_len == subflow->data_fin_tx_seq) {
|
||||
/* If there's an existing DSS mapping and it is the
|
||||
* final mapping, DATA_FIN consumes 1 additional byte of
|
||||
* mapping space.
|
||||
*/
|
||||
ext->data_fin = 1;
|
||||
ext->data_len++;
|
||||
}
|
||||
}
|
||||
|
@ -354,8 +355,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
|
|||
if (mpext)
|
||||
opts->ext_copy = *mpext;
|
||||
|
||||
if (skb && tcp_fin &&
|
||||
subflow->conn->sk_state != TCP_ESTABLISHED)
|
||||
if (skb && tcp_fin && subflow->data_fin_tx_enable)
|
||||
mptcp_write_data_fin(subflow, &opts->ext_copy);
|
||||
ret = true;
|
||||
}
|
||||
|
|
|
@ -419,6 +419,15 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
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);
|
||||
if (unlikely(ssock)) {
|
||||
fallback:
|
||||
|
@ -427,8 +436,6 @@ fallback:
|
|||
return ret >= 0 ? ret + copied : (copied ? copied : ret);
|
||||
}
|
||||
|
||||
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
|
||||
|
||||
ssk = mptcp_subflow_get(msk);
|
||||
if (!ssk) {
|
||||
release_sock(sk);
|
||||
|
@ -460,6 +467,7 @@ fallback:
|
|||
|
||||
ssk_check_wmem(msk, ssk);
|
||||
release_sock(ssk);
|
||||
out:
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
@ -712,7 +720,8 @@ static void mptcp_cancel_work(struct sock *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);
|
||||
|
||||
|
@ -725,6 +734,14 @@ static void mptcp_subflow_shutdown(struct sock *ssk, int how)
|
|||
tcp_disconnect(ssk, O_NONBLOCK);
|
||||
break;
|
||||
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;
|
||||
tcp_shutdown(ssk, how);
|
||||
break;
|
||||
|
@ -741,6 +758,7 @@ static void mptcp_close(struct sock *sk, long timeout)
|
|||
struct mptcp_subflow_context *subflow, *tmp;
|
||||
struct mptcp_sock *msk = mptcp_sk(sk);
|
||||
LIST_HEAD(conn_list);
|
||||
u64 data_fin_tx_seq;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
|
@ -749,11 +767,15 @@ static void mptcp_close(struct sock *sk, long timeout)
|
|||
|
||||
list_splice_init(&msk->conn_list, &conn_list);
|
||||
|
||||
data_fin_tx_seq = msk->write_seq;
|
||||
|
||||
release_sock(sk);
|
||||
|
||||
list_for_each_entry_safe(subflow, tmp, &conn_list, node) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -846,7 +868,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
|
|||
*err = -ENOBUFS;
|
||||
local_bh_enable();
|
||||
release_sock(sk);
|
||||
mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1);
|
||||
mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1, 0, 0);
|
||||
tcp_close(newsk, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1301,7 +1323,7 @@ static int mptcp_shutdown(struct socket *sock, int how)
|
|||
mptcp_for_each_subflow(msk, 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:
|
||||
|
|
|
@ -125,7 +125,9 @@ struct mptcp_subflow_context {
|
|||
mpc_map : 1,
|
||||
data_avail : 1,
|
||||
rx_eof : 1,
|
||||
data_fin_tx_enable : 1,
|
||||
can_ack : 1; /* only after processing the remote a key */
|
||||
u64 data_fin_tx_seq;
|
||||
|
||||
struct sock *tcp_sock; /* tcp sk backpointer */
|
||||
struct sock *conn; /* parent mptcp_sock */
|
||||
|
|
Loading…
Reference in New Issue