slackhq/nebula · error
csum_start is zero
Error message
csum_start is zero
What it means
SegmentTCP uses csumStart as the offset of the L4 (TCP) header within each stamped segment and to bound a valid IPv4 IHL. csum_start == 0 would place the TCP header at offset 0, overlapping the L3 header, which is never valid; the function rejects it immediately.
Source
Thrown at overlay/tio/virtio/segment_linux.go:219
sum += uint32(^uint16(seq >> 16))
sum += uint32(^uint16(seq))
sum += uint32(^flags)
sum += uint32(^binary.BigEndian.Uint16(pkt[csumStart+tcpChecksumOff : csumStart+tcpChecksumOff+2]))
sum = (sum & 0xffff) + (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16)
return sum
}
// SegmentTCP walks a TSO superpacket pkt, yielding each segment as a slice into pkt.
// Per-segment plaintext is laid out by stamping a copy of the original L3+L4 header into pkt at offset i*gsoSize,
// where it sits immediately before that segment's payload chunk in the original buffer.
// pkt is consumed by this call and must not be inspected by the caller after the final yield.
func SegmentTCP(pkt []byte, hdrLenU, csumStartU, gsoSizeU uint16, yield func(seg []byte) error) error {
if gsoSizeU == 0 {
return fmt.Errorf("gso_size is zero")
}
if csumStartU == 0 {
return fmt.Errorf("csum_start is zero")
}
headerLen := int(hdrLenU)
csumStart := int(csumStartU)
if headerLen > maxSegHdrLen {
return fmt.Errorf("header len %d exceeds max %d", headerLen, maxSegHdrLen)
}
isV4 := pkt[0]>>4 == 4
tcpHdrLen := int(pkt[csumStart+tcpDataOffOff]>>4) * 4
payLen := len(pkt) - headerLen
gsoSize := int(gsoSizeU)
numSeg := segCount(payLen, gsoSize)
origSeq := binary.BigEndian.Uint32(pkt[csumStart+tcpSeqOff : csumStart+tcpSeqOff+4])
origFlags := pkt[csumStart+tcpFlagsOff]
baseProtoSum := basePseudoSum(pkt, isV4, unix.IPPROTO_TCP)View on GitHub (pinned to dd8f660c0a)
Solutions
- Only call SegmentTCP for packets whose virtio-net header has VIRTIO_NET_HDR_F_NEEDS_CSUM set (csum_start > 0); otherwise handle the packet normally.
- Check that csum_start is read at the correct offset and byte order from the virtio-net header.
- Validate hdrLen < csumStart <= len(pkt)-TCP header before the call.
- If constructing headers yourself, set csum_start to the actual L4 offset (e.g. 20 for plain IPv4+TCP).
Example fix
// before
seg.SegmentTCP(pkt, hdrLen, 0, gsoSize, yield) // placeholder csum_start
// after
if !gsoHdr.NeedsCsum || gsoHdr.CsumStart == 0 {
return errors.New("packet has no checksum offload metadata")
}
seg.SegmentTCP(pkt, hdrLen, gsoHdr.CsumStart, gsoHdr.GsoSize, yield) Defensive patterns
Strategy: validation
Validate before calling
if gsoHdr.CsumStart == 0 || gsoHdr.CsumStart <= gsoHdr.HdrLen {
// not a needs-csum packet; do not call SegmentTCP
return handleWithoutOffload(pkt)
} Type guard
func needsCsum(vhdr VirtioNetHdr) bool { return vhdr.CsumStart > 0 && vhdr.GsoSize > 0 } Try / catch
err := segmenter.SegmentTCP(pkt, hdrLen, csumStart, gsoSize, yield)
if err != nil {
if strings.Contains(err.Error(), "csum_start is zero") {
return errors.New("packet lacks checksum-offload metadata; use normal TX path")
}
return err
} Prevention
- Gate segmentation on the VIRTIO_NET_HDR_F_NEEDS_CSUM flag, not on raw field values.
- Read csum_start at the correct offset/endianness from the virtio-net header.
- Never pass 0 as a placeholder csumStart; compute it from the actual L4 offset.
- Log-and-drop packets with csum_start == 0 at the RX boundary instead of pushing them downstream.
When it happens
Trigger: Calling SegmentTCP with csumStartU == 0 — the virtio-net header's csum_start field was 0 (packet is not a partially-checksummed/GSO packet), or the caller passed a zero-valued struct field by mistake.
Common situations: Routing non-offload packets into the segmentation path; zeroed virtio-net header because checksum offload wasn't negotiated; wrong struct layout/endianness when parsing the header; passing literal 0 as a placeholder for 'no offload'.
Related errors
- header len %d exceeds max %d
- packet is too short
- gso_size is zero
- ErrIPv6CouldNotFindPayload
- ErrBadDetailsVpnAddr
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/4e676d0439f31237.
Report an issue: GitHub.