Branch: refs/heads/misc-bugfixes Home: https://github.com/kronosnet/kronosnet Commit: c18743a6e70ad37e738fe5d5b13d87d23e1584d6 https://github.com/kronosnet/kronosnet/commit/c18743a6e70ad37e738fe5d5b13d87... Author: Fabio M. Di Nitto fdinitto@redhat.com Date: 2026-05-27 (Wed, 27 May 2026)
Changed paths: M libknet/transport_common.c
Log Message: ----------- libknet: switch internal socketpairs from SOCK_SEQPACKET to SOCK_DGRAM
FreeBSD 15 changed SOCK_SEQPACKET from atomic datagrams to stream sockets with record markers, requiring MSG_EOR to mark message boundaries.
For AF_UNIX local socketpairs, SOCK_DGRAM and SOCK_SEQPACKET are functionally equivalent: - Message boundaries preserved atomically - 100% reliable (no packet loss) - Ordered delivery guaranteed - No partial reads with properly sized buffers
SOCK_DGRAM provides native atomic message boundaries without MSG_EOR overhead.
Signed-off-by: Fabio M. Di Nitto fabbione@kronosnet.org Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com
Commit: cd49bfc586e43a55fcad05b6965f8e622699a9b2 https://github.com/kronosnet/kronosnet/commit/cd49bfc586e43a55fcad05b6965f8e... Author: Fabio M. Di Nitto fdinitto@redhat.com Date: 2026-05-27 (Wed, 27 May 2026)
Changed paths: M libknet/host.c
Log Message: ----------- libknet: fix defragmentation buffer reclamation logic
Fix two bugs in the defragmentation buffer reclamation logic that prevent efficient memory management:
1. Window calculation was using the old received sequence number (dst_seq_num) instead of the current packet's sequence number (seq_num) to calculate the valid buffer window. This caused buffers to be reclaimed based on stale sequence information, potentially freeing buffers that should still be valid or keeping buffers that should be reclaimed.
2. Window size calculation incorrectly used defrag_bufs_max (configuration limit, default 1024) instead of allocated_defrag_bufs (actual allocated count, typically 32) when allocated_defrag_bufs < defrag_bufs_max. This created an excessively large window (1025 sequence numbers for 32 buffer slots), causing integer wraparound in the tail calculation and preventing proper buffer reclamation.
Example: With seq_num=150, allocated_defrag_bufs=32, defrag_bufs_max=1024: - Buggy: tail = 150 - 1025 = -875 → wraps to 64661 (prevents reclamation) - Fixed: tail = 150 - 33 = 117 (correct reclamation window)
The window size must always match the actual allocated buffer capacity to ensure proper reclamation of stale defragmentation buffers.
Signed-off-by: Fabio M. Di Nitto fdinitto@redhat.com Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com
Commit: c53261302d08032e3df814ed9d0d13f29f1fcefd https://github.com/kronosnet/kronosnet/commit/c53261302d08032e3df814ed9d0d13... Author: Fabio M. Di Nitto fdinitto@redhat.com Date: 2026-05-27 (Wed, 27 May 2026)
Changed paths: M libknet/host.c
Log Message: ----------- libknet: fix sequence number wraparound calculation in defragmentation
The distance calculation between sequence numbers was incorrect when wraparound occurred. The formula was backwards: it subtracted in the wrong direction and didn't account for the +1 needed for modular arithmetic.
This caused incorrect buffer reclamation decisions near the SEQ_MAX boundary.
Practical examples (SEQ_MAX = 65535):
Example 1 - Normal case (no wraparound): Last packet: dst_seq_num = 1000 New packet: seq_num = 1005 Expected distance: 5
BEFORE (wrong): seq_dist = dst_seq_num - seq_num = 1000 - 1005 = -5 (negative!)
AFTER (correct): seq_dist = seq_num - dst_seq_num = 1005 - 1000 = 5
Example 2 - Wraparound case: Last packet: dst_seq_num = 65534 New packet: seq_num = 3 (wrapped around) Expected distance: 5 (65534→65535→0→1→2→3)
BEFORE (wrong): seq_dist = (SEQ_MAX - seq_num) + dst_seq_num seq_dist = (65535 - 3) + 65534 = 131066 (huge wrong number!)
AFTER (correct): seq_dist = (SEQ_MAX - dst_seq_num) + seq_num + 1 seq_dist = (65535 - 65534) + 3 + 1 = 5
The +1 accounts for the transition from 65535→0 being one step, not zero.
Verification that circular buffer cleaning is not broken:
The seq_dist value is used to determine whether the new packet is: a) Within the circular buffer window (seq_dist < KNET_CBUFFER_SIZE) b) Far enough to require full buffer clear (seq_dist > threshold) c) Should trigger incremental cleaning (fall through case)
Test case 1 - Normal sequential packet: dst_seq_num = 1000, seq_num = 1005, expected distance = 5
BEFORE: seq_dist = -5 (unsigned overflow ~65530) → Incorrectly clears entire buffer for normal sequential packets!
AFTER: seq_dist = 5 → Correctly identifies packet as within buffer window, no clearing needed
Test case 2 - Wraparound (close distance): dst_seq_num = 65534, seq_num = 3, expected distance = 5
BEFORE: seq_dist = 131066 → Falls through to circular buffer cleaning code incorrectly
AFTER: seq_dist = 5 → Correctly identifies packet as within buffer window
Test case 3 - Large jump requiring buffer clear: dst_seq_num = 1000, seq_num = 50000, expected distance = 49000
BEFORE: seq_dist = -49000 (unsigned ~16536) → Clears buffer (correct by accident)
AFTER: seq_dist = 49000 → Clears buffer (correct by design)
The circular buffer cleaning code (lines 673-684) uses seq_num and dst_seq_num directly via modulo operations to find buffer positions. It does not use seq_dist for position calculations, only for the threshold check to determine whether to run. The fix corrects the threshold logic without affecting the position calculations.
Signed-off-by: Fabio M. Di Nitto fdinitto@redhat.com Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com
Commit: 82a5abb422a77bf9ba9b26ed9148e3d2820f98ae https://github.com/kronosnet/kronosnet/commit/82a5abb422a77bf9ba9b26ed9148e3... Author: Fabio M. Di Nitto fdinitto@redhat.com Date: 2026-05-27 (Wed, 27 May 2026)
Changed paths: M libknet/tests/Makefile.am A libknet/tests/int_seq_wraparound_stress.c
Log Message: ----------- [tests] add comprehensive sequence number wraparound stress test
Add new int_seq_wraparound_stress_test that validates sequence number wraparound handling and defragmentation buffer management under realistic packet loss scenarios.
Test scenarios:
1. Normal sequential with packet loss - validates basic packet handling with gaps in sequence numbers. Sends seq 1000-1006 with some complete (both fragments), some lost (no fragments), and some incomplete (only one fragment). Verifies only complete packets are delivered (4/7).
2. Wraparound boundary with packet loss - validates wraparound crossing from seq 65533 to seq 4 with mixed complete/incomplete/lost packets. Tests special case where sequence numbers wrap from SEQ_MAX (65535) to 0. Verifies 5 complete packets delivered correctly across boundary.
3. Large sequence jump (> KNET_CBUFFER_SIZE) - validates buffer clearing logic when sequence gap exceeds circular buffer size. Sends seq 5000, then jumps to 10000 (5000 packet gap > KNET_CBUFFER_SIZE 4096), triggering buffer reclamation. Verifies all complete packets delivered.
4. Out-of-order fragment delivery - validates fragment assembly when fragments arrive in reverse order (frag 2 before frag 1) for same sequence number. Sends 3 packets with mixed fragment ordering and verifies all packets assembled correctly regardless of fragment order.
5. Out-of-order complete packet delivery - validates handling when complete packets arrive with out-of-order sequence numbers. Sends seq 1000, 1001, 999 (last one arrives late) and verifies all 3 packets are delivered.
6. Extreme packet loss beyond receive window - validates recovery from massive packet loss exceeding KNET_CBUFFER_SIZE. Creates incomplete packets at seq 30000-30002, then jumps to 35000 (5000 gap), tests buffer clearing and continued operation. Verifies 5 complete packets.
7. Wraparound with extreme packet loss - validates wraparound combined with massive loss. Sends seq 60000-60001, then jumps to 100-103 (gap = 5636 packets wrapping around + exceeding buffer size). Verifies buffer clearing across wraparound and 5 complete packets.
8. Wraparound stress with multiple cycles and duplicate detection - rapidly cycles through wraparound boundary (65530-65535-0-10) twice with different packet filters. First cycle sends packets where (seq % 3) != 0, second cycle sends packets where (seq % 3) != 1. Tests duplicate rejection and verifies only unique sequence numbers are delivered.
9. Fragment corruption across wraparound - validates protection against historical bug where fragments from different packet transmissions could be incorrectly mixed. Sends seq 5000 frag 1 filled with 'A', advances through complete wraparound (65536 sequences), sends seq 5000 frag 2 filled with 'B'. Verifies old fragment 1 was invalidated and no corrupted packet delivered (mixing A+B fragments).
10. Defragmentation buffer reclamation window calculation - validates _reclaim_old_defrag_bufs() correctly reclaims buffers outside current sequence window using seq_num (not dst_seq_num). Creates incomplete fragments at seq 100, 105, 110, 115, 120, then advances window to seq 150. Verifies buffers outside window (100-115) are reclaimed and buffer within window (120) is preserved.
11. Circular buffer clearing at boundaries - validates _seq_num_lookup correctly clears circular_buffer ranges in both wraparound (tail > head) and normal (tail <= head) cases. Test case 1: seq 3000 → 10 creates tail=3001 > head=10, should clear [3001..4095] and [0..10]. Test case 2: seq jump to 8191 creates tail=0 <= head=4095, should clear [0..4095].
Signed-off-by: Fabio M. Di Nitto fabbione@kronosnet.org Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com
Commit: d56d3bc7b7a1de092b9934a3a6c5fb6726e9b1be https://github.com/kronosnet/kronosnet/commit/d56d3bc7b7a1de092b9934a3a6c5fb... Author: Fabio M. Di Nitto fdinitto@redhat.com Date: 2026-05-27 (Wed, 27 May 2026)
Changed paths: M libknet/tests/Makefile.am A libknet/tests/int_defrag_edge_cases.c
Log Message: ----------- [tests] add defragmentation edge cases test suite
Add new int_defrag_edge_cases_test that validates critical defragmentation buffer management scenarios not covered by existing tests.
Test scenarios:
1. Last fragment arriving first - validates special buffer positioning at KNET_MAX_PACKET_SIZE - len offset, last_first flag handling, and fragment relocation when packet completes. Tests asymmetric MTU with fragments in order [3/3, 1/3, 2/3] and verifies data integrity across all fragments (280 bytes total with distinct payloads 'A', 'B', 'C').
2. Buffer exhaustion and reclamation - validates window-based reclamation when all 32 defrag buffers are filled with incomplete packets. Sends new complete packet with distant sequence number (9000 vs 2000-2031) triggering reclamation of all out-of-window buffers. Verifies data integrity with no corruption from old buffer data in new packet.
3. Fragment data overwrite protection - validates correct assembly of large fragmented packets without buffer overflow. Test case 1 sends 100 fragments × 500 bytes (50,000 bytes total), test case 2 sends 50 fragments × 1,300 bytes (65,000 bytes approaching KNET_MAX_PACKET_SIZE). Each fragment filled with its index number and verified on assembly.
4. Duplicate fragment handling - validates that duplicate fragments (same sequence number and fragment index) are silently rejected without corrupting the buffer. Sends frag 1/2, frag 1/2 (duplicate with different data), frag 2/2 and verifies only one correct packet is delivered with original fragment data preserved.
5. Maximum realistic fragments - validates fragment map can handle high fragment counts (100 fragments, 500 bytes each = 50,000 bytes total). PCKT_FRAG_MAX (255) is theoretical limit, but realistic max is determined by min_mtu. Tests worst-case scenario with min MTU ~550 bytes.
6. Single fragment packets (1/1) - validates degenerate case where packets are marked as fragmented but contain only one fragment. Sends 5 packets of 200 bytes each, all marked as 1/1, and verifies correct delivery without unnecessary defragmentation overhead.
7. Interleaved fragment assembly across wraparound - validates concurrent assembly of multiple fragmented packets with fragments arriving in interleaved order across sequence number wraparound boundary. Sends 4 packets (seq 65534, 65535, 0, 1) with all first fragments, then completes them in reverse order (1→0→65535→65534). Verifies all packets received correctly with no cross-contamination between defrag buffers.
Signed-off-by: Fabio M. Di Nitto fabbione@kronosnet.org Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com
Commit: fa33598730673f382751fcdfafa9b65bf6c606fc https://github.com/kronosnet/kronosnet/commit/fa33598730673f382751fcdfafa9b6... Author: Fabio M. Di Nitto fdinitto@redhat.com Date: 2026-05-27 (Wed, 27 May 2026)
Changed paths: M libknet/tests/Makefile.am A libknet/tests/int_buffer_management.c
Log Message: ----------- [tests] add defragmentation buffer management test suite
Add new int_buffer_management_test that validates dynamic defragmentation buffer allocation, growth, shrinking, and reuse scenarios.
Test scenarios:
1. Dynamic buffer growth - validates automatic buffer reallocation when all defrag buffers are in use. Fills all 32 initial buffers with incomplete packets (fragment 1/2 only), then sends one additional packet to trigger growth. Verifies buffer allocation doubles from 32 to 64 and packet reception works correctly after reallocation.
2. Buffer reuse after reclamation - validates that reclaimed buffers are properly cleared before reuse, preventing data leakage. Sends incomplete packet at seq 5000 filled with 'X', then complete packet at seq 10000 (distance 5000 > KNET_CBUFFER_SIZE 4096) triggering reclamation. Verifies new packet contains only 'Z' with no trace of 'X', then reuses same buffer with new packet 'M'+'N' and confirms no leakage.
3. Dynamic buffer shrinking - validates automatic buffer deallocation when usage stays below threshold. Starting from 64 buffers (grown in test 1), clears all incomplete packets to achieve low usage, reduces defrag_bufs_usage_samples from 255 to 10 for faster testing, then sends complete packets over 10+ sample periods (1 second each) to trigger shrinking. Verifies buffers halve from 64 to 32 and packet reception works correctly after shrinking.
Signed-off-by: Fabio M. Di Nitto fabbione@kronosnet.org Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com
Commit: 0d5b2c4c71cd132caa1bac6c87eef0671f33b6c6 https://github.com/kronosnet/kronosnet/commit/0d5b2c4c71cd132caa1bac6c87eef0... Author: Fabio M. Di Nitto fdinitto@redhat.com Date: 2026-05-27 (Wed, 27 May 2026)
Changed paths: M libknet/handle_api.c M libknet/host.c M libknet/internals.h M libknet/threads_rx.c M libknet/threads_tx.c M libknet/transport_common.c M libknet/transport_common.h
Log Message: ----------- libknet: add is_seqpacket flag and MSG_EOR support for user-provided sockets
User-provided SOCK_SEQPACKET sockets via knet_handle_add_datafd() require MSG_EOR for FreeBSD 15+ compatibility.
Add is_seqpacket flag to knet_sock structure to track socket type. Detect SOCK_SEQPACKET via getsockopt(SOL_SOCKET, SO_TYPE) when user provides a datafd.
Update writev_all() to use sendmsg() with MSG_EOR for SEQPACKET sockets, preserving record boundaries. DGRAM sockets continue using writev().
Internal knet-created socketpairs (now SOCK_DGRAM) set is_seqpacket=0. User-provided SOCK_SEQPACKET sockets set is_seqpacket=1.
Signed-off-by: Fabio M. Di Nitto fabbione@kronosnet.org Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com
Compare: https://github.com/kronosnet/kronosnet/compare/a0a031eb9824...0d5b2c4c71cd
To unsubscribe from these emails, change your notification settings at https://github.com/kronosnet/kronosnet/settings/notifications