From 4fe14eda3f1a1d47b10e4e418e32eed518a1af88 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Wed, 16 Sep 2026 15:52:03 -0700 Subject: [PATCH] Frame: add hardware checksum offload and TSO metadata - Add RX transport checksum validation flags and hardware checksum value reporting - Add TX partial-checksum offload start/store offsets - Add TSO segment size and IPv6 super-packet support - Fix inverted guard conditions in aggregate buffer length handling --- Sources/SwiftNetwork/Protocols/Frame.swift | 112 +++++++++++++++++- .../SwiftNetworkFrameTests.swift | 4 +- 2 files changed, 111 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftNetwork/Protocols/Frame.swift b/Sources/SwiftNetwork/Protocols/Frame.swift index b98e3934..07c33198 100644 --- a/Sources/SwiftNetwork/Protocols/Frame.swift +++ b/Sources/SwiftNetwork/Protocols/Frame.swift @@ -507,6 +507,12 @@ public struct Frame: ~Copyable { static let isChecksumIPChecked = Flags(rawValue: 1 << 1) static let isChecksumIPValid = Flags(rawValue: 1 << 2) static let fragmentationOverride = Flags(rawValue: 1 << 3) + // RX: the hardware validated the transport (TCP/UDP) checksum. + static let isChecksumDataValid = Flags(rawValue: 1 << 4) + // RX: the validated checksum value already folds in the pseudo-header. + static let isChecksumPseudoHeader = Flags(rawValue: 1 << 5) + // TX: the TSO segment size below describes an IPv6 super-packet. + static let isTSOIPv6 = Flags(rawValue: 1 << 6) } var flags: Flags = Flags() var serviceClass = Parameters.ServiceClass.bestEffort @@ -514,6 +520,22 @@ public struct Frame: ~Copyable { var dscpValue: UInt8? var hopLimit: UInt8 = 0 var checksumOffloadFlags: UInt8 = 0 + + // TX partial-checksum offload: byte offset (from the packet start / IP header) + // where the NIC begins the 1's-complement sum, and where it stores the result. + // Zero for the IP-header-only case, which the NIC locates itself. + var checksumStartOffset: UInt16 = 0 + var checksumStoreOffset: UInt16 = 0 + + // TX segmentation offload (TSO): the per-segment TCP payload size the + // hardware should cut this frame into, or 0 for an ordinary single-segment + // frame. A non-zero value means the frame's payload deliberately exceeds + // the path MTU. + var tsoSegmentSize: UInt16 = 0 + + // RX: the final/partial transport checksum value the hardware reported. + var hardwareChecksumValue: UInt16 = 0 + var departureTime: UInt64 = 0 // departure time at which kernel should send the packet, used for kernel pacing var isLastPacket: Bool { get { flags.contains(.isLastPacket) } @@ -527,6 +549,14 @@ public struct Frame: ~Copyable { get { flags.contains(.isChecksumIPValid) } set { if newValue { flags.insert(.isChecksumIPValid) } else { flags.remove(.isChecksumIPValid) } } } + var isChecksumDataValid: Bool { + get { flags.contains(.isChecksumDataValid) } + set { if newValue { flags.insert(.isChecksumDataValid) } else { flags.remove(.isChecksumDataValid) } } + } + var isChecksumPseudoHeader: Bool { + get { flags.contains(.isChecksumPseudoHeader) } + set { if newValue { flags.insert(.isChecksumPseudoHeader) } else { flags.remove(.isChecksumPseudoHeader) } } + } var fragmentationOverride: Bool? { get { flags.contains(.fragmentationOverride) ? true : nil } set { @@ -581,14 +611,14 @@ public struct Frame: ~Copyable { var packetChainTotalLength: Int { get { - guard !isSingleIPAggregate else { + guard isSingleIPAggregate else { Logger.proto.fault("Attempt to get aggregate buffer length on a non-single IP aggregate") return 0 } return aggregateBufferLength } set { - guard !isSingleIPAggregate else { + guard isSingleIPAggregate else { Logger.proto.fault("Attempt to get aggregate buffer length on a non-single IP aggregate") return } @@ -697,6 +727,82 @@ public struct Frame: ~Copyable { } } + var isChecksumDataValid: Bool { + get { ipPacketValues?.isChecksumDataValid ?? false } + set { + if ipPacketValues == nil { + ipPacketValues = IPPacketValues() + } + ipPacketValues!.isChecksumDataValid = newValue + } + } + + var isChecksumPseudoHeader: Bool { + get { ipPacketValues?.isChecksumPseudoHeader ?? false } + set { + if ipPacketValues == nil { + ipPacketValues = IPPacketValues() + } + ipPacketValues!.isChecksumPseudoHeader = newValue + } + } + + var checksumStartOffset: UInt16 { + get { ipPacketValues?.checksumStartOffset ?? 0 } + set { + if ipPacketValues == nil { + ipPacketValues = IPPacketValues() + } + ipPacketValues!.checksumStartOffset = newValue + } + } + + var checksumStoreOffset: UInt16 { + get { ipPacketValues?.checksumStoreOffset ?? 0 } + set { + if ipPacketValues == nil { + ipPacketValues = IPPacketValues() + } + ipPacketValues!.checksumStoreOffset = newValue + } + } + + var hardwareChecksumValue: UInt16 { + get { ipPacketValues?.hardwareChecksumValue ?? 0 } + set { + if ipPacketValues == nil { + ipPacketValues = IPPacketValues() + } + ipPacketValues!.hardwareChecksumValue = newValue + } + } + + // Per-segment TCP payload size for a TSO super-packet, 0 when this frame is an + // ordinary single-segment frame. + var tsoSegmentSize: UInt16 { + get { ipPacketValues?.tsoSegmentSize ?? 0 } + set { + if ipPacketValues == nil { + ipPacketValues = IPPacketValues() + } + ipPacketValues!.tsoSegmentSize = newValue + } + } + + var isTSOIPv6: Bool { + get { ipPacketValues?.flags.contains(.isTSOIPv6) ?? false } + set { + if ipPacketValues == nil { + ipPacketValues = IPPacketValues() + } + if newValue { + ipPacketValues!.flags.insert(.isTSOIPv6) + } else { + ipPacketValues!.flags.remove(.isTSOIPv6) + } + } + } + struct FrameProtocolMetadata: ~Copyable { var uuid: SystemUUID var metadata: AbstractProtocolMetadata @@ -726,7 +832,7 @@ public struct Frame: ~Copyable { mutating func reduceAggregateBufferLength(by length: Int) { if isSingleIPAggregate { - guard aggregateBufferLength < length else { + guard length <= aggregateBufferLength else { let existingLength = aggregateBufferLength Logger.proto.fault("Aggregate buffer length \(existingLength) cannot remove \(length)") aggregateBufferLength = 0 diff --git a/Tests/SwiftNetworkTests/SwiftNetworkFrameTests.swift b/Tests/SwiftNetworkTests/SwiftNetworkFrameTests.swift index 6d4f283c..9ecfdafb 100644 --- a/Tests/SwiftNetworkTests/SwiftNetworkFrameTests.swift +++ b/Tests/SwiftNetworkTests/SwiftNetworkFrameTests.swift @@ -18,7 +18,7 @@ import XCTest @available(anyAppleOS 27, *) final class SwiftNetworkFrameTests: XCTestCase { func testFrameLayout() { - XCTAssertEqual(MemoryLayout.size, 136) - XCTAssertEqual(MemoryLayout.stride, 136) + XCTAssertEqual(MemoryLayout.size, 144) + XCTAssertEqual(MemoryLayout.stride, 144) } }