From 6a01607004fa20da75ba757109efbf18e0b47a8a Mon Sep 17 00:00:00 2001 From: Our Air Quality Date: Sat, 5 Aug 2017 19:18:21 +1000 Subject: [PATCH] tcp_out rto: delay re-transmission earlier if link writes are deferred. There is already a guard in tcp_output_segment() for a pbuf still being referenced by the netif driver due to deferred transmission, however the callers are modifying state even when this gives up. It seems cleaner to have the callers guard this case and avoid modifying their state. tcp_rexmit_rto() might better avoid re-transmission of any segments if any of the unacked segments are deferred, to avoid loading the link further if it is struggling to flush its buffered writes. Link level queues can be limited on some devices and need spares for link management. --- src/core/tcp_out.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 2cf2de9e..d744ed65 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -1523,6 +1523,16 @@ tcp_rexmit_rto(struct tcp_pcb *pcb) return; } + /* Give up if any of the segment pbufs are still referenced by the netif + driver due to deferred transmission. No point loading the link further if + it is struggling to flush its buffered writes. */ + for (seg = pcb->unacked; seg != NULL; seg = seg->next) { + if (seg->p->ref != 1) { + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit_rto busy\n")); + return; + } + } + /* Move all unacked segments to the head of the unsent queue */ for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); /* concatenate unsent queue after unacked queue */ @@ -1572,9 +1582,17 @@ tcp_rexmit(struct tcp_pcb *pcb) return; } + seg = pcb->unacked; + + /* Give up if the first segment pbuf is still referenced by the netif driver + due to deferred transmission. */ + if (seg->p->ref != 1) { + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit busy\n")); + return; + } + /* Move the first unacked segment to the unsent queue */ /* Keep the unsent queue sorted. */ - seg = pcb->unacked; pcb->unacked = seg->next; cur_seg = &(pcb->unsent); @@ -1614,6 +1632,13 @@ void tcp_rexmit_fast(struct tcp_pcb *pcb) { if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) { + /* Give up if the first segment pbuf is still referenced by the netif driver + due to deferred transmission. */ + if (pcb->unacked->p->ref != 1) { + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_rexmit_fast busy\n")); + return; + } + /* This is fast retransmit. Retransmit the first unacked segment. */ LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F