Skip to content

perf: port upstream gopacket removal + IpAssoc wiring (ee7a476)#263

Open
full-bars wants to merge 9 commits into
mainfrom
perf/upstream-gopacket-removal
Open

perf: port upstream gopacket removal + IpAssoc wiring (ee7a476)#263
full-bars wants to merge 9 commits into
mainfrom
perf/upstream-gopacket-removal

Conversation

@full-bars

Copy link
Copy Markdown
Owner

Ports the gopacket elimination, packet stats infrastructure, and
IpAssoc/block-action wiring from upstream commit ee7a476 (perf fixes

  • SDK support). This is the highest-risk PR of the 4-PR sequence —
    it touches the fork's most-customized files (ip.go, ip_remote_multi_client.go).

Depends on PR #261's new files (ip_assoc.go, ip_block_action.go,
memory_budget.go, transfer_contract_stats.go).

Changes by file

ip.go (~1042 lines changed)

gopacket removal (all hot paths):

  • Removes github.com/google/gopacket and gopacket/layers imports
  • Custom IPProtocol, UDPPort, TCPPort types replace gopacket types
  • Manual binary parse functions: parseIpv4, parseIpv6, parseUdpPacket, parseTcpPacket
  • Manual binary write functions: writeIpv4Header, writeIpv6Header, writeTcpHeader
  • Checksum helpers: checksumAdd, checksumFinish, transportChecksum
  • Hot-path dispatch (runShard, ParseIpPathWithPayload) uses manual parsing
  • UDP/TCP write paths (DataPackets, SynAck, PureAck, etc.) use manual binary encoding

ip_remote_multi_client.go (+63 lines)

  • multiClientConfig atomic pointer replaces separate performanceProfile + localSecurityBypass fields
  • SetServerNameLookup() — new method for SNI-free ServerName affinity routing
  • Lock-free reads on hot path via config.Load()

ip_udp_write_pipeline_leak_test.go

  • Updated to use new UDPPort/parsedUdp types instead of gopacket

Fork features preserved

  • All DPI modifications, contract metrics, bandwidth tracking, active connection counting
  • Fork's simplified SecurityPolicy interface (unary Inspect, no ctx, no Refresh methods)
  • IngressSecurityPolicyGenerator/EgressSecurityPolicyGenerator fields
  • All rate-limited logging and [net][s]select promotion

Build verification

  • go build . — clean
  • go build ./provider/ — clean
  • go vet . — clean
  • go test -short ./provider/ — 7.5s, all pass

Adds 11 new files from upstream connect main (ahead of v2026.7.6-985989570):

New files — no behavioural changes to existing code:
- ip_assoc.go (1135L) — activity-based IP co-association matrix
- ip_block_action.go (570L) — block action overrides for security policy
- memory_budget.go (56L) — process-wide memory budget scaling
- transfer_memory_budget.go (74L) — shared byte budget for sequences
- transfer_contract_stats.go (164L) — per-contract usage event callbacks
- egress.go / egress_net.go / egress_other.go / egress_windows.go (181L) — egress interface binding
- transfer_peer_manager.go (166L) — peer tracking from control messages
- race_on_test.go / race_off_test.go — test helpers for race detection

Supporting additions to existing files:
- protocol/frame.pb.go, protocol/transfer.pb.go — regenerated for new message types
- transfer.go — Peer, NetworkPeer types
- util.go — memoryShedders, AddMemoryShedder, ShedMemory
- ip_remote_multi_client.go — ServerNameLookup interface, EventEpoch field + default
- transfer_contract_manager.go — SignStoredContract, VerifyStoredContract, NetworkEventTimeChangeHmac field, ContractStatsEpoch field, contract stats struct fields

New files compile against the fork's existing interfaces. Test files
that depend on not-yet-ported methods (block actions, packet stats,
IpAssoc wiring) are deferred to later PRs.
Changes ReceiveFunction signature from `provideMode protocol.ProvideMode`
to `peer Peer` (upstream 83dc999). Updates all 7 source file signatures,
4 test file lambdas, and connectctl. Adds ProvideMode_Network to the
contract-manager pause filter so network peers don't fall back to stream
contracts when paused.
Replaces gopacket-based packet parsing/building with manual binary
encoding on all hot paths in ip.go. Adds packet stats, ipPath caching,
and lock-free multiClientConfig refactoring in ip_remote_multi_client.go.

- Removes github.com/google/gopacket dependency from ip.go
- Custom IPProtocol/UDPPort/TCPPort types + manual IPv4/IPv6/TCP/UDP
  parse and write functions
- New fields: ipAssoc, blockAction state, packetStats on RemoteUserNatMultiClient
- Atomic config pointer replaces separate performanceProfile + localSecurityBypass fields
- Test file updated to use new types
runShard's bare `return` on parse failure exited the whole loop, firing
defer self.cancel() and killing the shard permanently on a single
malformed TCP/UDP segment from any client (remote DoS). Changed to
continue so only the bad packet is dropped.

Also add the len(ipPacket) == 0 guard in ParseIpPathWithPayload that
upstream's reference port includes, preventing an index-out-of-range
panic on an empty packet.
…gaps

Five issues found in independent review of the gopacket-removal port:

1. tcpPacket()/SynAck() computed the TCP checksum over the header only,
   excluding payload/options. Every TCP data segment sent to clients
   carried an invalid checksum and would be silently dropped by
   standard client network stacks. Fixed to checksum the full segment,
   matching the UDP path.

2. parseWindowScaleOpts didn't handle TCP option kinds 0 (EOL) and 1
   (NOP), which have no length byte. Since real SYNs almost always
   place a NOP before the Window Scale option, the parser desynced and
   missed WS for nearly all real clients. Fixed to handle both.

3. SynAck() allocated an unpadded options buffer (3 bytes) while
   writeTcpHeader's data-offset field rounds up to a 4-byte boundary
   (24), producing a segment 1 byte shorter than its own header claims.
   Receiving stacks reject this as truncated. Fixed to pad options to
   a 4-byte boundary (zero-fill reads as EOL).

4. tcpSend's RST branch didn't return ipPacket to the message pool on
   an existing-sequence teardown, unlike the sibling no-syn-drop branch.
   Fixed to return it.

5. runShard's ipVersion switch had no default case, leaking the pool
   buffer for any packet with a first nibble outside {4, 6}. Fixed to
   add one, matching the existing per-protocol default branches.
- Extract the TCP window-scale option parser from TcpSequence.Run()'s
  inline closure to a package-level exported function for testability.
- Add ip_packet_test.go with 33 tests covering:
  - checksumAdd/checksumFinish (RFC 1071)
  - transportChecksum (pseudo-header + segment)
  - TCP checksum scope (payload, options)
  - ConnectionState PureAck/RstAck packet construction
  - parseIpv4/parseIpv6/parseUdpPacket/parseTcpPacket round trips
  - ParseTcpWindowScaleOpts (nil, empty, WS, cap-at-14, NOP, EOL,
    unknown options, multi-NOP)
  - writeIpv4Header/writeIpv6Header/writeTcpHeader round trips
  - flowHash (IPv4/IPv6 consistency, short packets)
  - malformed packet guards (nil, empty, invalid data offset)
  - SynAck data-offset/segment-length consistency
  - UDP checksum non-zero invariant
- Fix TestChecksumAddAndFinish expected value.
Adds unit-level checksumAdd/checksumFinish coverage, PureAck/RstAck
construction tests, parseIpv4/parseIpv6/parseUdpPacket/parseTcpPacket
round trips, writeIpv4Header/writeIpv6Header/writeTcpHeader round
trips, malformed/too-short input guards, empty-packet guard, and
flow-hash edge cases, on top of the checksum-scope and window-scale
option tests from the prior commit.

Fixed one flaky test in the process: TestWriteIpv4RoundTrip verified
the IPv4 checksum over the full allocated buffer (including 8 bytes
of unrelated UDP-header space past the 20-byte IP header), which only
holds when the message pool happens to hand back a zeroed buffer.
Pool buffers aren't guaranteed zeroed on reuse, so this failed
intermittently depending on prior test pool state. Scoped the
verification to the actual 20-byte IPv4 header, matching what
writeIpv4Header itself checksums. Verified with -shuffle=on across
multiple runs after the fix.
@full-bars full-bars force-pushed the perf/upstream-gopacket-removal branch 2 times, most recently from f6728b3 to c4065b4 Compare July 13, 2026 08:04
Covers c4065b4's fix directly: StreamState.DataPackets (UDP) and
ConnectionState.DataPackets (TCP) both now error on mtu <= header
size instead of divide-by-zero / negative-capacity panicking.
Verified against the unfixed code — reproduces the exact
"makeslice: cap out of range" panic from the audit report.
@full-bars full-bars force-pushed the perf/upstream-gopacket-removal branch from 4519357 to 069a964 Compare July 13, 2026 10:39
@full-bars full-bars self-assigned this Jul 13, 2026
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.

1 participant