From 53c6f565e2c867c41bbdb5d1143ee6f32c9002f3 Mon Sep 17 00:00:00 2001 From: Pavel Siska Date: Mon, 4 May 2026 14:26:50 +0200 Subject: [PATCH] ipfix: fix stuck flushing loop after TCP disconnect in LZ4 mode In LZ4 compress mode, a failed send_packet() call in send_templates() left readSize non-zero, causing the next getWriteBuffer() in send_data() to return null and exit without clearing template buffers. Fix by adding CompressBuffer::getWriteBufferOrReset() which resets via shrinkTo(0) and retries once on null. --- src/plugins/output/ipfix/src/ipfix.cpp | 14 +++++++++++--- src/plugins/output/ipfix/src/ipfix.hpp | 11 +++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/plugins/output/ipfix/src/ipfix.cpp b/src/plugins/output/ipfix/src/ipfix.cpp index 2095d28ed..94cc54b25 100644 --- a/src/plugins/output/ipfix/src/ipfix.cpp +++ b/src/plugins/output/ipfix/src/ipfix.cpp @@ -818,10 +818,8 @@ void IPFIXExporter::send_data() * Loop ends when len = create_data_packet() is 0 */ while (true) { - pkt.data = packetDataBuffer.getWriteBuffer(mtu); + pkt.data = packetDataBuffer.getWriteBufferOrReset(mtu); if (!pkt.data) { - // this should never happen because packetDataBuffer - // should already have enough allocated memory return; } @@ -1227,6 +1225,16 @@ int CompressBuffer::init(bool compress, size_t compressSize, size_t writeSize) return 0; } +uint8_t* CompressBuffer::getWriteBufferOrReset(size_t requiredSize) +{ + uint8_t* buffer = getWriteBuffer(requiredSize); + if (buffer != nullptr) { + return buffer; + } + shrinkTo(0); + return getWriteBuffer(requiredSize); +} + uint8_t* CompressBuffer::getWriteBuffer(size_t requiredSize) { // the contents can happily fit into the buffer diff --git a/src/plugins/output/ipfix/src/ipfix.hpp b/src/plugins/output/ipfix/src/ipfix.hpp index d2f7e9f74..38cd8f230 100644 --- a/src/plugins/output/ipfix/src/ipfix.hpp +++ b/src/plugins/output/ipfix/src/ipfix.hpp @@ -457,6 +457,17 @@ class CompressBuffer { */ uint8_t* getWriteBuffer(size_t requiredSize); + /** + * @brief Attempts to get a write buffer, resetting internal state on failure and retrying once. + * + * This can happen in compress mode when a previous send failed without calling + * compress(), leaving readSize non-zero and causing getWriteBuffer() to return null. + * + * @param requiredSize required size of the buffer + * @return pointer to the buffer with the required size, null on failure + */ + uint8_t* getWriteBufferOrReset(size_t requiredSize); + /** * @brief compresses data written after last compress() call *