net: tcp: Retrigger the send work in case of loopback

In case a loopback or own address is used in TCP connection, the TCP
stack delegates the acatual data send to a workqueue. This is fine,
however it could lead to some aritificial delays in case a lot of data
is being sent before the workqueue has a chance to execute queued work
items. In such case, we only sent a single packet, when many could've
already been queued.

Fix this, by resubmitting the queue in case a local address is used, and
there's still more packets pending for send.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2022-03-23 13:07:34 +01:00 committed by Carles Cufí
commit 2e9866f88f

View file

@ -51,6 +51,7 @@ static struct k_work_q tcp_work_q;
static K_KERNEL_STACK_DEFINE(work_q_stack, CONFIG_NET_TCP_WORKQ_STACK_SIZE); static K_KERNEL_STACK_DEFINE(work_q_stack, CONFIG_NET_TCP_WORKQ_STACK_SIZE);
static void tcp_in(struct tcp *conn, struct net_pkt *pkt); static void tcp_in(struct tcp *conn, struct net_pkt *pkt);
static bool is_destination_local(struct net_pkt *pkt);
int (*tcp_send_cb)(struct net_pkt *pkt) = NULL; int (*tcp_send_cb)(struct net_pkt *pkt) = NULL;
size_t (*tcp_recv_cb)(struct tcp *conn, struct net_pkt *pkt) = NULL; size_t (*tcp_recv_cb)(struct tcp *conn, struct net_pkt *pkt) = NULL;
@ -454,6 +455,7 @@ static bool tcp_send_process_no_lock(struct tcp *conn)
{ {
bool unref = false; bool unref = false;
struct net_pkt *pkt; struct net_pkt *pkt;
bool local = false;
pkt = tcp_slist(conn, &conn->send_queue, peek_head, pkt = tcp_slist(conn, &conn->send_queue, peek_head,
struct net_pkt, next); struct net_pkt, next);
@ -489,6 +491,10 @@ static bool tcp_send_process_no_lock(struct tcp *conn)
goto out; goto out;
} }
if (is_destination_local(pkt)) {
local = true;
}
tcp_send(pkt); tcp_send(pkt);
if (forget == false && if (forget == false &&
@ -501,6 +507,9 @@ static bool tcp_send_process_no_lock(struct tcp *conn)
if (conn->in_retransmission) { if (conn->in_retransmission) {
k_work_reschedule_for_queue(&tcp_work_q, &conn->send_timer, k_work_reschedule_for_queue(&tcp_work_q, &conn->send_timer,
K_MSEC(tcp_rto)); K_MSEC(tcp_rto));
} else if (local && !sys_slist_is_empty(&conn->send_queue)) {
k_work_reschedule_for_queue(&tcp_work_q, &conn->send_timer,
K_NO_WAIT);
} }
out: out: