cancel
Showing results for 
Search instead for 
Did you mean: 

lwIP / TCP tx'd pbuf ACK'd?

LCE
Principal

Hello,

I have to admit that this is more a question concerning lwIP, but as I'm using a STM32F7...

And the search engines haven't helped yet.

I need to transmit TCP packets quickly, without waiting for TCP's ACK.

Payload for these packets come from an array of DMA buffers (sourced by SAI) which I might need for other interfaces, like USB output, not at the same time though.

Each of these buffers is given a state, like FREE, WRITING, TRANSMITTING, WAIT_ACK.

So I give a buffer to lwIP with tcp_write() (building its own pbuf) and call tcp_output() immediately.

Most examples I found also set the tcp_sent callback, and only continue transmitting after the latest data has been ACK'd by the receiver. I have no time for that, wireshark showed me that ACK can take a few milli seconds - too long.

I've been through lwIP's TCP functions, but I cannot find how to pass back the info from lwIP which pbuf / data was recently ACK'd to free the DMA buffers.

tcp_sent() length does not help, because all DMA buffers are the same size.

Any hints or ideas?

I hope there's something I have not yet understood or have overseen.

I could start fiddling within the lwIP functions, but I hope there's a more elegant way.

PS: otherwise zero-copy TX ethernet is working, as is http, PTP

13 REPLIES 13
Piranha
Chief II

You misunderstood my idea. The buffer size as such doesn't matter and same size buffers are even slightly easier. And the callback most likely will be called for TCP segments, the size of which is not guaranteed to directly correspond to your buffers.

err_t tcp_sent_fn(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
	static size_t nbSent_;
	
	for (nbSent_ += len; nbSent_ >= BUF_SIZE; nbSent_ -= BUF_SIZE) {
		// Free the next buffer
	}
}

Okay, so I have to assume and hope that packets will be acknowledged in the right order.

I had the hope that I could solve that a little smarter, in case some older packet is not ACK'd and must be sent again.

Until now, Wireshark shows that ACKs are coming quite quick and "linear".

But now I have just one device with 6.4 Mbit/s, it might go up to 4 devices (via Gb-switch) with ~ 50 Mbit/s each.

But first things first, let's get one up with 50 Mbps...

As the TCP presents an ordered stream (not packets) to the application, the callback must be called sequentially. Otherwise such API doesn't make a sense at all. Also I found a confirmation here:

https://lists.gnu.org/archive/html/lwip-users/2022-02/msg00003.html

LCE
Principal

Update:

I had Piranha's solution implemented, counting sent/ACK'd bytes and freeing buffers.

But I found that this was not good enough, every few hours there was some late ACK (when a retransmission was needed I think), so this kind of "linear" scheme combined with linear source buffers (SAIs -> DMA) was blocking at some point, yet with other buffers free.

So I built a queue for the source buffers,

added a custom pbuf variable with a pointer to the source buffer,

copied and changed tcp_write() for that application which adds the corresponding pointer to the pbuf,

and added in pbuf_free() that if that pointer is not NULL, then the source buffer's state changes to free.

Learned a lot about lwIP...

But still feels awkward having changed some lwIP stuff.