Commit 0fa1b378 authored by Geliang Tang's avatar Geliang Tang Committed by Jakub Kicinski

mptcp: use get_send wrapper

This patch adds the multiple subflows support for __mptcp_push_pending
and __mptcp_subflow_push_pending. Use get_send() wrapper instead of
mptcp_subflow_get_send() in them.

Check the subflow scheduled flags to test which subflow or subflows are
picked by the scheduler, use them to send data.

Move msk_owned_by_me() and fallback checks into get_send() wrapper from
mptcp_subflow_get_send().

This commit allows the scheduler to set the subflow->scheduled bit in
multiple subflows, but it does not allow for sending redundant data.
Multiple scheduled subflows will send sequential data on each subflow.
Reviewed-by: default avatarMat Martineau <martineau@kernel.org>
Signed-off-by: default avatarGeliang Tang <geliang.tang@suse.com>
Signed-off-by: default avatarMat Martineau <martineau@kernel.org>
Link: https://lore.kernel.org/r/20230821-upstream-net-next-20230818-v1-8-0c860fb256a8@kernel.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 07336a87
...@@ -1377,15 +1377,6 @@ struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk) ...@@ -1377,15 +1377,6 @@ struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
u64 linger_time; u64 linger_time;
long tout = 0; long tout = 0;
msk_owned_by_me(msk);
if (__mptcp_check_fallback(msk)) {
if (!msk->first)
return NULL;
return __tcp_can_send(msk->first) &&
sk_stream_memory_free(msk->first) ? msk->first : NULL;
}
/* pick the subflow with the lower wmem/wspace ratio */ /* pick the subflow with the lower wmem/wspace ratio */
for (i = 0; i < SSK_MODE_MAX; ++i) { for (i = 0; i < SSK_MODE_MAX; ++i) {
send_info[i].ssk = NULL; send_info[i].ssk = NULL;
...@@ -1538,43 +1529,56 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags) ...@@ -1538,43 +1529,56 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags)
.flags = flags, .flags = flags,
}; };
bool do_check_data_fin = false; bool do_check_data_fin = false;
int push_count = 1;
while (mptcp_send_head(sk)) { while (mptcp_send_head(sk) && (push_count > 0)) {
struct mptcp_subflow_context *subflow;
int ret = 0; int ret = 0;
prev_ssk = ssk; if (mptcp_sched_get_send(msk))
ssk = mptcp_subflow_get_send(msk); break;
/* First check. If the ssk has changed since push_count = 0;
* the last round, release prev_ssk
*/
if (ssk != prev_ssk && prev_ssk)
mptcp_push_release(prev_ssk, &info);
if (!ssk)
goto out;
/* Need to lock the new subflow only if different mptcp_for_each_subflow(msk, subflow) {
* from the previous one, otherwise we are still if (READ_ONCE(subflow->scheduled)) {
* helding the relevant lock mptcp_subflow_set_scheduled(subflow, false);
*/
if (ssk != prev_ssk)
lock_sock(ssk);
ret = __subflow_push_pending(sk, ssk, &info); prev_ssk = ssk;
if (ret <= 0) { ssk = mptcp_subflow_tcp_sock(subflow);
if (ret == -EAGAIN) if (ssk != prev_ssk) {
continue; /* First check. If the ssk has changed since
mptcp_push_release(ssk, &info); * the last round, release prev_ssk
goto out; */
if (prev_ssk)
mptcp_push_release(prev_ssk, &info);
/* Need to lock the new subflow only if different
* from the previous one, otherwise we are still
* helding the relevant lock
*/
lock_sock(ssk);
}
push_count++;
ret = __subflow_push_pending(sk, ssk, &info);
if (ret <= 0) {
if (ret != -EAGAIN ||
(1 << ssk->sk_state) &
(TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | TCPF_CLOSE))
push_count--;
continue;
}
do_check_data_fin = true;
}
} }
do_check_data_fin = true;
} }
/* at this point we held the socket lock for the last subflow we used */ /* at this point we held the socket lock for the last subflow we used */
if (ssk) if (ssk)
mptcp_push_release(ssk, &info); mptcp_push_release(ssk, &info);
out:
/* ensure the rtx timer is running */ /* ensure the rtx timer is running */
if (!mptcp_timer_pending(sk)) if (!mptcp_timer_pending(sk))
mptcp_reset_timer(sk); mptcp_reset_timer(sk);
...@@ -1588,30 +1592,49 @@ static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk, bool ...@@ -1588,30 +1592,49 @@ static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk, bool
struct mptcp_sendmsg_info info = { struct mptcp_sendmsg_info info = {
.data_lock_held = true, .data_lock_held = true,
}; };
bool keep_pushing = true;
struct sock *xmit_ssk; struct sock *xmit_ssk;
int copied = 0; int copied = 0;
info.flags = 0; info.flags = 0;
while (mptcp_send_head(sk)) { while (mptcp_send_head(sk) && keep_pushing) {
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
int ret = 0; int ret = 0;
/* check for a different subflow usage only after /* check for a different subflow usage only after
* spooling the first chunk of data * spooling the first chunk of data
*/ */
xmit_ssk = first ? ssk : mptcp_subflow_get_send(msk); if (first) {
if (!xmit_ssk) mptcp_subflow_set_scheduled(subflow, false);
goto out; ret = __subflow_push_pending(sk, ssk, &info);
if (xmit_ssk != ssk) { first = false;
mptcp_subflow_delegate(mptcp_subflow_ctx(xmit_ssk), if (ret <= 0)
MPTCP_DELEGATE_SEND); break;
copied += ret;
continue;
}
if (mptcp_sched_get_send(msk))
goto out; goto out;
if (READ_ONCE(subflow->scheduled)) {
mptcp_subflow_set_scheduled(subflow, false);
ret = __subflow_push_pending(sk, ssk, &info);
if (ret <= 0)
keep_pushing = false;
copied += ret;
} }
ret = __subflow_push_pending(sk, ssk, &info); mptcp_for_each_subflow(msk, subflow) {
first = false; if (READ_ONCE(subflow->scheduled)) {
if (ret <= 0) xmit_ssk = mptcp_subflow_tcp_sock(subflow);
break; if (xmit_ssk != ssk) {
copied += ret; mptcp_subflow_delegate(subflow,
MPTCP_DELEGATE_SEND);
keep_pushing = false;
}
}
}
} }
out: out:
......
...@@ -99,6 +99,19 @@ int mptcp_sched_get_send(struct mptcp_sock *msk) ...@@ -99,6 +99,19 @@ int mptcp_sched_get_send(struct mptcp_sock *msk)
struct mptcp_subflow_context *subflow; struct mptcp_subflow_context *subflow;
struct mptcp_sched_data data; struct mptcp_sched_data data;
msk_owned_by_me(msk);
/* the following check is moved out of mptcp_subflow_get_send */
if (__mptcp_check_fallback(msk)) {
if (msk->first &&
__tcp_can_send(msk->first) &&
sk_stream_memory_free(msk->first)) {
mptcp_subflow_set_scheduled(mptcp_subflow_ctx(msk->first), true);
return 0;
}
return -EINVAL;
}
mptcp_for_each_subflow(msk, subflow) { mptcp_for_each_subflow(msk, subflow) {
if (READ_ONCE(subflow->scheduled)) if (READ_ONCE(subflow->scheduled))
return 0; return 0;
......
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