mptcp: trigger msk processing even for OoO data

This is a prerequisite to allow receiving data from multiple
subflows without re-injection.

Instead of dropping the OoO - "future" data in
subflow_check_data_avail(), call into __mptcp_move_skbs()
and let the msk drop that.

To avoid code duplication factor out the mptcp_subflow_discard_data()
helper.

Note that __mptcp_move_skbs() can now find multiple subflows
with data avail (comprising to-be-discarded data), so must
update the byte counter incrementally.

v1 -> v2:
 - fix checkpatch issues (unsigned -> unsigned int)

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Paolo Abeni
2020-09-14 10:01:09 +02:00
committed by David S. Miller
parent 47bebdf365
commit 6719331c2f
3 changed files with 78 additions and 42 deletions

View File

@@ -816,6 +816,40 @@ static int subflow_read_actor(read_descriptor_t *desc,
return copy_len;
}
int mptcp_subflow_discard_data(struct sock *ssk, unsigned int limit)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
u32 map_remaining;
size_t delta;
map_remaining = subflow->map_data_len -
mptcp_subflow_get_map_offset(subflow);
delta = min_t(size_t, limit, map_remaining);
/* discard mapped data */
pr_debug("discarding %zu bytes, current map len=%d", delta,
map_remaining);
if (delta) {
read_descriptor_t desc = {
.count = delta,
};
int ret;
ret = tcp_read_sock(ssk, &desc, subflow_read_actor);
if (ret < 0) {
ssk->sk_err = -ret;
return ret;
}
if (ret < delta)
return 0;
if (delta == map_remaining) {
subflow->data_avail = 0;
subflow->map_valid = 0;
}
}
return 0;
}
static bool subflow_check_data_avail(struct sock *ssk)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
@@ -832,8 +866,6 @@ static bool subflow_check_data_avail(struct sock *ssk)
msk = mptcp_sk(subflow->conn);
for (;;) {
u32 map_remaining;
size_t delta;
u64 ack_seq;
u64 old_ack;
@@ -851,7 +883,7 @@ static bool subflow_check_data_avail(struct sock *ssk)
subflow->map_data_len = skb->len;
subflow->map_subflow_seq = tcp_sk(ssk)->copied_seq -
subflow->ssn_offset;
subflow->data_avail = 1;
subflow->data_avail = MPTCP_SUBFLOW_DATA_AVAIL;
return true;
}
@@ -880,43 +912,19 @@ static bool subflow_check_data_avail(struct sock *ssk)
pr_debug("msk ack_seq=%llx subflow ack_seq=%llx", old_ack,
ack_seq);
if (ack_seq == old_ack) {
subflow->data_avail = 1;
subflow->data_avail = MPTCP_SUBFLOW_DATA_AVAIL;
break;
} else if (after64(ack_seq, old_ack)) {
subflow->data_avail = MPTCP_SUBFLOW_OOO_DATA;
break;
}
/* only accept in-sequence mapping. Old values are spurious
* retransmission; we can hit "future" values on active backup
* subflow switch, we relay on retransmissions to get
* in-sequence data.
* Cuncurrent subflows support will require subflow data
* reordering
* retransmission
*/
map_remaining = subflow->map_data_len -
mptcp_subflow_get_map_offset(subflow);
if (before64(ack_seq, old_ack))
delta = min_t(size_t, old_ack - ack_seq, map_remaining);
else
delta = min_t(size_t, ack_seq - old_ack, map_remaining);
/* discard mapped data */
pr_debug("discarding %zu bytes, current map len=%d", delta,
map_remaining);
if (delta) {
read_descriptor_t desc = {
.count = delta,
};
int ret;
ret = tcp_read_sock(ssk, &desc, subflow_read_actor);
if (ret < 0) {
ssk->sk_err = -ret;
goto fatal;
}
if (ret < delta)
return false;
if (delta == map_remaining)
subflow->map_valid = 0;
}
if (mptcp_subflow_discard_data(ssk, old_ack - ack_seq))
goto fatal;
return false;
}
return true;