Skip to content

Commit 6c039a1

Browse files
committed
tun: export optimized IP checksum funcs
External implementers of tun.Device may support GRO, requiring checksum offload. Signed-off-by: Jordan Whited <[email protected]>
1 parent 60eeedf commit 6c039a1

File tree

5 files changed

+23
-18
lines changed

5 files changed

+23
-18
lines changed

tun/checksum.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,9 @@ func pseudoHeaderChecksum32(protocol uint8, srcAddr, dstAddr []byte, totalLen ui
702702
return foldedSum
703703
}
704704

705-
func pseudoHeaderChecksum(protocol uint8, srcAddr, dstAddr []byte, totalLen uint16) uint16 {
705+
// PseudoHeaderChecksum computes an IP pseudo-header checksum. srcAddr and
706+
// dstAddr must be 4 or 16 bytes in length.
707+
func PseudoHeaderChecksum(protocol uint8, srcAddr, dstAddr []byte, totalLen uint16) uint16 {
706708
if strconv.IntSize < 64 {
707709
return pseudoHeaderChecksum32(protocol, srcAddr, dstAddr, totalLen)
708710
}

tun/checksum_amd64.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ package tun
22

33
import "golang.org/x/sys/cpu"
44

5-
// checksum computes an IP checksum starting with the provided initial value.
6-
// The length of data should be at least 128 bytes for best performance. Smaller
7-
// buffers will still compute a correct result. For best performance with
8-
// smaller buffers, use shortChecksum().
95
var checksum = checksumAMD64
106

7+
// Checksum computes an IP checksum starting with the provided initial value.
8+
// The length of data should be at least 128 bytes for best performance. Smaller
9+
// buffers will still compute a correct result.
10+
func Checksum(data []byte, initial uint16) uint16 {
11+
return checksum(data, initial)
12+
}
13+
1114
func init() {
1215
if cpu.X86.HasAVX && cpu.X86.HasAVX2 && cpu.X86.HasBMI2 {
1316
checksum = checksumAVX2

tun/checksum_generic.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package tun
77

88
import "strconv"
99

10-
func checksum(data []byte, initial uint16) uint16 {
10+
func Checksum(data []byte, initial uint16) uint16 {
1111
if strconv.IntSize < 64 {
1212
return checksumGeneric32(data, initial)
1313
}

tun/offload.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func GSOSplit(in []byte, options GSOOptions, outBufs [][]byte, sizes []int, outO
102102
// the checksum we compute. This is typically the pseudo-header sum.
103103
initial := binary.BigEndian.Uint16(in[cSumAt:])
104104
in[cSumAt], in[cSumAt+1] = 0, 0
105-
binary.BigEndian.PutUint16(in[cSumAt:], ^checksum(in[options.CsumStart:], initial))
105+
binary.BigEndian.PutUint16(in[cSumAt:], ^Checksum(in[options.CsumStart:], initial))
106106
}
107107
sizes[0] = copy(outBufs[0][outOffset:], in)
108108
return 1, nil
@@ -179,7 +179,7 @@ func GSOSplit(in []byte, options GSOOptions, outBufs [][]byte, sizes []int, outO
179179
}
180180
out[10], out[11] = 0, 0 // clear ipv4 header checksum
181181
binary.BigEndian.PutUint16(out[2:], uint16(totalLen))
182-
ipv4CSum := ^checksum(out[:iphLen], 0)
182+
ipv4CSum := ^Checksum(out[:iphLen], 0)
183183
binary.BigEndian.PutUint16(out[10:], ipv4CSum)
184184
} else {
185185
// For IPv6 we are responsible for updating the payload length field.
@@ -210,8 +210,8 @@ func GSOSplit(in []byte, options GSOOptions, outBufs [][]byte, sizes []int, outO
210210
out[transportCsumAt], out[transportCsumAt+1] = 0, 0 // clear tcp/udp checksum
211211
transportHeaderLen := int(options.HdrLen - options.CsumStart)
212212
lenForPseudo := uint16(transportHeaderLen + segmentDataLen)
213-
transportCSum := pseudoHeaderChecksum(protocol, in[srcAddrOffset:srcAddrOffset+addrLen], in[srcAddrOffset+addrLen:srcAddrOffset+addrLen*2], lenForPseudo)
214-
transportCSum = ^checksum(out[options.CsumStart:totalLen], transportCSum)
213+
transportCSum := PseudoHeaderChecksum(protocol, in[srcAddrOffset:srcAddrOffset+addrLen], in[srcAddrOffset+addrLen:srcAddrOffset+addrLen*2], lenForPseudo)
214+
transportCSum = ^Checksum(out[options.CsumStart:totalLen], transportCSum)
215215
binary.BigEndian.PutUint16(out[options.CsumStart+options.CsumOffset:], transportCSum)
216216

217217
nextSegmentDataAt += int(options.GSOSize)

tun/offload_linux.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,8 @@ func checksumValid(pkt []byte, iphLen, proto uint8, isV6 bool) bool {
410410
addrSize = 16
411411
}
412412
lenForPseudo := uint16(len(pkt) - int(iphLen))
413-
cSum := pseudoHeaderChecksum(proto, pkt[srcAddrAt:srcAddrAt+addrSize], pkt[srcAddrAt+addrSize:srcAddrAt+addrSize*2], lenForPseudo)
414-
return ^checksum(pkt[iphLen:], cSum) == 0
413+
cSum := PseudoHeaderChecksum(proto, pkt[srcAddrAt:srcAddrAt+addrSize], pkt[srcAddrAt+addrSize:srcAddrAt+addrSize*2], lenForPseudo)
414+
return ^Checksum(pkt[iphLen:], cSum) == 0
415415
}
416416

417417
// coalesceResult represents the result of attempting to coalesce two TCP
@@ -659,7 +659,7 @@ func applyTCPCoalesceAccounting(bufs [][]byte, offset int, table *tcpGROTable) e
659659
hdr.gsoType = unix.VIRTIO_NET_HDR_GSO_TCPV4
660660
pkt[10], pkt[11] = 0, 0
661661
binary.BigEndian.PutUint16(pkt[2:], uint16(len(pkt))) // set new total length
662-
iphCSum := ^checksum(pkt[:item.iphLen], 0) // compute IPv4 header checksum
662+
iphCSum := ^Checksum(pkt[:item.iphLen], 0) // compute IPv4 header checksum
663663
binary.BigEndian.PutUint16(pkt[10:], iphCSum) // set IPv4 header checksum field
664664
}
665665
err := hdr.encode(bufs[item.bufsIndex][offset-virtioNetHdrLen:])
@@ -679,8 +679,8 @@ func applyTCPCoalesceAccounting(bufs [][]byte, offset int, table *tcpGROTable) e
679679
srcAddrAt := offset + addrOffset
680680
srcAddr := bufs[item.bufsIndex][srcAddrAt : srcAddrAt+addrLen]
681681
dstAddr := bufs[item.bufsIndex][srcAddrAt+addrLen : srcAddrAt+addrLen*2]
682-
psum := pseudoHeaderChecksum(unix.IPPROTO_TCP, srcAddr, dstAddr, uint16(len(pkt)-int(item.iphLen)))
683-
binary.BigEndian.PutUint16(pkt[hdr.csumStart+hdr.csumOffset:], checksum([]byte{}, psum))
682+
psum := PseudoHeaderChecksum(unix.IPPROTO_TCP, srcAddr, dstAddr, uint16(len(pkt)-int(item.iphLen)))
683+
binary.BigEndian.PutUint16(pkt[hdr.csumStart+hdr.csumOffset:], Checksum([]byte{}, psum))
684684
} else {
685685
hdr := virtioNetHdr{}
686686
err := hdr.encode(bufs[item.bufsIndex][offset-virtioNetHdrLen:])
@@ -716,7 +716,7 @@ func applyUDPCoalesceAccounting(bufs [][]byte, offset int, table *udpGROTable) e
716716
} else {
717717
pkt[10], pkt[11] = 0, 0
718718
binary.BigEndian.PutUint16(pkt[2:], uint16(len(pkt))) // set new total length
719-
iphCSum := ^checksum(pkt[:item.iphLen], 0) // compute IPv4 header checksum
719+
iphCSum := ^Checksum(pkt[:item.iphLen], 0) // compute IPv4 header checksum
720720
binary.BigEndian.PutUint16(pkt[10:], iphCSum) // set IPv4 header checksum field
721721
}
722722
err := hdr.encode(bufs[item.bufsIndex][offset-virtioNetHdrLen:])
@@ -739,8 +739,8 @@ func applyUDPCoalesceAccounting(bufs [][]byte, offset int, table *udpGROTable) e
739739
srcAddrAt := offset + addrOffset
740740
srcAddr := bufs[item.bufsIndex][srcAddrAt : srcAddrAt+addrLen]
741741
dstAddr := bufs[item.bufsIndex][srcAddrAt+addrLen : srcAddrAt+addrLen*2]
742-
psum := pseudoHeaderChecksum(unix.IPPROTO_UDP, srcAddr, dstAddr, uint16(len(pkt)-int(item.iphLen)))
743-
binary.BigEndian.PutUint16(pkt[hdr.csumStart+hdr.csumOffset:], checksum([]byte{}, psum))
742+
psum := PseudoHeaderChecksum(unix.IPPROTO_UDP, srcAddr, dstAddr, uint16(len(pkt)-int(item.iphLen)))
743+
binary.BigEndian.PutUint16(pkt[hdr.csumStart+hdr.csumOffset:], Checksum([]byte{}, psum))
744744
} else {
745745
hdr := virtioNetHdr{}
746746
err := hdr.encode(bufs[item.bufsIndex][offset-virtioNetHdrLen:])

0 commit comments

Comments
 (0)