Skip to content

framebuffer: add configurable frame lifetime and drop stale frames#87

Open
maxwelllls wants to merge 1 commit into
mguentner:masterfrom
maxwelllls:framebuffer
Open

framebuffer: add configurable frame lifetime and drop stale frames#87
maxwelllls wants to merge 1 commit into
mguentner:masterfrom
maxwelllls:framebuffer

Conversation

@maxwelllls
Copy link
Copy Markdown

Add a configurable frame lifetime for buffered CAN/CAN FD frames.

This change introduces the -g command-line option to configure the maximum frame age in microseconds (default: 1000000, 0 disables the check), and passes that setting to both the network and CAN frame buffers.

FrameBuffer now stores an enqueue timestamp for each frame using a monotonic clock and drops expired frames when reading from the main buffer. It also removes expired frames from the intermediate buffer before they can be forwarded.

This avoids replaying large amounts of stale buffered traffic after the bus or transport path recovers.

Add a configurable frame lifetime for buffered CAN/CAN FD frames.

This change introduces the `-g` command-line option to configure the
maximum frame age in microseconds (default: 1000000, `0` disables the
check), and passes that setting to both the network and CAN frame
buffers.

FrameBuffer now stores an enqueue timestamp for each frame using a
monotonic clock and drops expired frames when reading from the main
buffer. It also removes expired frames from the intermediate buffer
before they can be forwarded.

This avoids replaying large amounts of stale buffered traffic after the
bus or transport path recovers.
Copy link
Copy Markdown
Owner

@mguentner mguentner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution. Can you please clarify under which circumstances you encounter issues that require this feature?

I am not sure yet that the issues need to be solved by that amount of complexity.
As I have outlined, I believe that the "CAN -> Network" path may only require solving for TCP as UDP clears out frames "automatically" as it is fire and forget.

Note:
I actually I see more of an issue here with CANThread. Imagine that here we cannot send for a long time. The CANThread aggressively tries to transmit frames. I think there should be a limit, either temporal (like your PR) or attempts. Since we do not differentiate between "bus is broken" and "arbitrage not possible due to bus load", counting loops is kinda hard.

CANThread could maintain its own map of *frame -> timestamp which it uses to determine whether a frame should be retried on the next run or dropped.

Comment thread cannelloni.cpp
uint16_t localPort = 20000;
std::string canInterfaceName = "vcan0";
uint32_t bufferTimeout = 100000;
uint32_t frameLifetime = 1000000;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is 10x of the bufferTimeout. Since bufferTimeout < frameLifetime, this is already solved for UDP connections (at least in the default settings):

  • after a maximum of 100ms, the frames will have been sent
  • the framebuffer will no longer contain these frames

However since TCP connections require an active peer, here we need to deal with the TCP connection
becoming stale.

In TcpThread::flushFrameBuffer, cannelloni disconnects on write errors - this will happen after some time on a stale TCP connection. But here some frames may remain in the buffer, all the ones that could not be sent.

Comment thread tcpthread.cpp
ssize_t encodedBytes = encodeFrame(transmitBuffer, frame);
ssize_t bytesWritten = send(m_socket, transmitBuffer, encodedBytes, 0);
if (encodedBytes != bytesWritten) {
disconnect();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As written above, here we could remove all frames from the intermediateBuffer (put them back to the pool).

@maxwelllls
Copy link
Copy Markdown
Author

maxwelllls commented Apr 20, 2026

Thanks for the detailed feedback.

I have opened an issue describing the full problem scenario, including the background, the observed behavior, and the specific kind of change that is actually needed to address it.

After reviewing the code and your comments again, I realized that my current PR goes beyond the minimal scope required to fix that issue. This is on my side, and is mainly due to my still limited understanding of some parts of the codebase when I first tried to implement the change.

I will rework this PR, reduce the scope, and submit a narrower set of commits focused only on the specific issue. I need a bit more time to reproduce and validate the revised behavior properly on my setup before pushing the updated commits here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants