mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Move checksum to its own package and optimize bufferv2 checksumming.
Checksum capabilities are logically separate from tcpip header definitions and operations. It makes sense to extract this logic into its own package. This is also necessary to avoid circular dependencies with bufferv2. PiperOrigin-RevId: 473096480
This commit is contained in:
committed by
gVisor bot
parent
f7855b28f0
commit
22ca20c0f1
@@ -47,6 +47,7 @@ go_library(
|
||||
"//pkg/pool",
|
||||
"//pkg/refsvfs2",
|
||||
"//pkg/sync",
|
||||
"//pkg/tcpip/checksum",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -59,6 +60,7 @@ go_test(
|
||||
library = ":bufferv2",
|
||||
deps = [
|
||||
"//pkg/state",
|
||||
"//pkg/tcpip/checksum",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -20,6 +20,8 @@ package bufferv2
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
)
|
||||
|
||||
// Buffer is a non-linear buffer.
|
||||
@@ -443,6 +445,24 @@ func (b *Buffer) SubApply(offset, length int, fn func(*View)) {
|
||||
}
|
||||
}
|
||||
|
||||
// Checksum calculates a checksum over the buffer's payload starting at offset.
|
||||
func (b *Buffer) Checksum(offset int) uint16 {
|
||||
if offset >= int(b.size) {
|
||||
return 0
|
||||
}
|
||||
var v *View
|
||||
for v = b.data.Front(); v != nil && offset >= v.Size(); v = v.Next() {
|
||||
offset -= v.Size()
|
||||
}
|
||||
|
||||
var cs checksum.Checksumer
|
||||
cs.Add(v.AsSlice()[offset:])
|
||||
for v = v.Next(); v != nil; v = v.Next() {
|
||||
cs.Add(v.AsSlice())
|
||||
}
|
||||
return cs.Checksum()
|
||||
}
|
||||
|
||||
// Merge merges the provided Buffer with this one.
|
||||
//
|
||||
// The other Buffer will be appended to v, and other will be empty after this
|
||||
|
||||
@@ -19,11 +19,13 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/state"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
)
|
||||
|
||||
func BenchmarkReadAt(b *testing.B) {
|
||||
@@ -876,3 +878,23 @@ func TestRangeLen(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestChecksum(t *testing.T) {
|
||||
data := make([]byte, 100)
|
||||
rand.Read(data)
|
||||
|
||||
b := MakeWithData(data[:30])
|
||||
b.appendOwned(NewViewWithData(data[30:70]))
|
||||
b.appendOwned(NewViewWithData(data[70:]))
|
||||
|
||||
for offset := 0; offset < 100; offset++ {
|
||||
var cs checksum.Checksumer
|
||||
cs.Add(data[offset:])
|
||||
dataChecksum := cs.Checksum()
|
||||
bufChecksum := b.Checksum(offset)
|
||||
|
||||
if dataChecksum != bufChecksum {
|
||||
t.Errorf("(%#v).Checksum(%d) = %d, want %d", b, offset, bufChecksum, dataChecksum)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/bufferv2",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/checksum",
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/seqnum",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
|
||||
)
|
||||
@@ -506,7 +507,7 @@ func TCP(checkers ...TransportChecker) NetworkChecker {
|
||||
|
||||
tcp := header.TCP(last.Payload())
|
||||
payload := tcp.Payload()
|
||||
payloadChecksum := header.Checksum(payload, 0)
|
||||
payloadChecksum := checksum.Checksum(payload, 0)
|
||||
if !tcp.IsChecksumValid(first.SourceAddress(), first.DestinationAddress(), payloadChecksum, uint16(len(payload))) {
|
||||
t.Errorf("Bad checksum, got = %d", tcp.Checksum())
|
||||
}
|
||||
@@ -1042,7 +1043,7 @@ func ICMPv4Checksum() TransportChecker {
|
||||
}
|
||||
heldChecksum := icmpv4.Checksum()
|
||||
icmpv4.SetChecksum(0)
|
||||
newChecksum := ^header.Checksum(icmpv4, 0)
|
||||
newChecksum := ^checksum.Checksum(icmpv4, 0)
|
||||
icmpv4.SetChecksum(heldChecksum)
|
||||
if heldChecksum != newChecksum {
|
||||
t.Errorf("unexpected ICMP checksum, got = %d, want = %d", heldChecksum, newChecksum)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
load("//tools:defs.bzl", "go_library", "go_test")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
go_test(
|
||||
name = "checksum_test",
|
||||
srcs = ["checksum_test.go"],
|
||||
library = ":checksum",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "checksum",
|
||||
srcs = ["checksum.go"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
@@ -0,0 +1,216 @@
|
||||
// Copyright 2018 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package checksum provides the implementation of the encoding and decoding of
|
||||
// network protocol headers.
|
||||
package checksum
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// Size is the size of a checksum.
|
||||
//
|
||||
// The checksum is held in a uint16 which is 2 bytes.
|
||||
const Size = 2
|
||||
|
||||
// Put puts the checksum in the provided byte slice.
|
||||
func Put(b []byte, xsum uint16) {
|
||||
binary.BigEndian.PutUint16(b, xsum)
|
||||
}
|
||||
|
||||
func calculateChecksum(buf []byte, odd bool, initial uint32) (uint16, bool) {
|
||||
v := initial
|
||||
|
||||
if odd {
|
||||
v += uint32(buf[0])
|
||||
buf = buf[1:]
|
||||
}
|
||||
|
||||
l := len(buf)
|
||||
odd = l&1 != 0
|
||||
if odd {
|
||||
l--
|
||||
v += uint32(buf[l]) << 8
|
||||
}
|
||||
|
||||
for i := 0; i < l; i += 2 {
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
}
|
||||
|
||||
return Combine(uint16(v), uint16(v>>16)), odd
|
||||
}
|
||||
|
||||
func unrolledCalculateChecksum(buf []byte, odd bool, initial uint32) (uint16, bool) {
|
||||
v := initial
|
||||
|
||||
if odd {
|
||||
v += uint32(buf[0])
|
||||
buf = buf[1:]
|
||||
}
|
||||
|
||||
l := len(buf)
|
||||
odd = l&1 != 0
|
||||
if odd {
|
||||
l--
|
||||
v += uint32(buf[l]) << 8
|
||||
}
|
||||
for (l - 64) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
i += 16
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
i += 16
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
i += 16
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
buf = buf[64:]
|
||||
l = l - 64
|
||||
}
|
||||
if (l - 32) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
i += 16
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
buf = buf[32:]
|
||||
l = l - 32
|
||||
}
|
||||
if (l - 16) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
buf = buf[16:]
|
||||
l = l - 16
|
||||
}
|
||||
if (l - 8) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
buf = buf[8:]
|
||||
l = l - 8
|
||||
}
|
||||
if (l - 4) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
buf = buf[4:]
|
||||
l = l - 4
|
||||
}
|
||||
|
||||
// At this point since l was even before we started unrolling
|
||||
// there can be only two bytes left to add.
|
||||
if l != 0 {
|
||||
v += (uint32(buf[0]) << 8) + uint32(buf[1])
|
||||
}
|
||||
|
||||
return Combine(uint16(v), uint16(v>>16)), odd
|
||||
}
|
||||
|
||||
// Old calculates the checksum (as defined in RFC 1071) of the bytes in
|
||||
// the given byte array. This function uses a non-optimized implementation. Its
|
||||
// only retained for reference and to use as a benchmark/test. Most code should
|
||||
// use the header.Checksum function.
|
||||
//
|
||||
// The initial checksum must have been computed on an even number of bytes.
|
||||
func Old(buf []byte, initial uint16) uint16 {
|
||||
s, _ := calculateChecksum(buf, false, uint32(initial))
|
||||
return s
|
||||
}
|
||||
|
||||
// Checksum calculates the checksum (as defined in RFC 1071) of the bytes in the
|
||||
// given byte array. This function uses an optimized unrolled version of the
|
||||
// checksum algorithm.
|
||||
//
|
||||
// The initial checksum must have been computed on an even number of bytes.
|
||||
func Checksum(buf []byte, initial uint16) uint16 {
|
||||
s, _ := unrolledCalculateChecksum(buf, false, uint32(initial))
|
||||
return s
|
||||
}
|
||||
|
||||
// Checksumer calculates checksum defined in RFC 1071.
|
||||
type Checksumer struct {
|
||||
sum uint16
|
||||
odd bool
|
||||
}
|
||||
|
||||
// Add adds b to checksum.
|
||||
func (c *Checksumer) Add(b []byte) {
|
||||
if len(b) > 0 {
|
||||
c.sum, c.odd = unrolledCalculateChecksum(b, c.odd, uint32(c.sum))
|
||||
}
|
||||
}
|
||||
|
||||
// Checksum returns the latest checksum value.
|
||||
func (c *Checksumer) Checksum() uint16 {
|
||||
return c.sum
|
||||
}
|
||||
|
||||
// Combine combines the two uint16 to form their checksum. This is done
|
||||
// by adding them and the carry.
|
||||
//
|
||||
// Note that checksum a must have been computed on an even number of bytes.
|
||||
func Combine(a, b uint16) uint16 {
|
||||
v := uint32(a) + uint32(b)
|
||||
return uint16(v + v>>16)
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
// Copyright 2019 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package header provides the implementation of the encoding and decoding of
|
||||
// network protocol headers.
|
||||
package checksum
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestChecksumer(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
data [][]byte
|
||||
want uint16
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "OneOddView",
|
||||
data: [][]byte{
|
||||
{1, 9, 0, 5, 4},
|
||||
},
|
||||
want: 1294,
|
||||
},
|
||||
{
|
||||
name: "TwoOddViews",
|
||||
data: [][]byte{
|
||||
{1, 9, 0, 5, 4},
|
||||
{4, 3, 7, 1, 2, 123},
|
||||
},
|
||||
want: 33819,
|
||||
},
|
||||
{
|
||||
name: "OneEvenView",
|
||||
data: [][]byte{
|
||||
{1, 9, 0, 5},
|
||||
},
|
||||
want: 270,
|
||||
},
|
||||
{
|
||||
name: "TwoEvenViews",
|
||||
data: [][]byte{
|
||||
[]byte{98, 1, 9, 0},
|
||||
[]byte{9, 0, 5, 4},
|
||||
},
|
||||
want: 30981,
|
||||
},
|
||||
{
|
||||
name: "ThreeViews",
|
||||
data: [][]byte{
|
||||
{77, 11, 33, 0, 55, 44},
|
||||
{98, 1, 9, 0, 5, 4},
|
||||
{4, 3, 7, 1, 2, 123, 99},
|
||||
},
|
||||
want: 34236,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var all bytes.Buffer
|
||||
var c Checksumer
|
||||
for _, b := range tc.data {
|
||||
c.Add(b)
|
||||
// Append to the buffer. We will check the checksum as a whole later.
|
||||
if _, err := all.Write(b); err != nil {
|
||||
t.Fatalf("all.Write(b) = _, %s; want _, nil", err)
|
||||
}
|
||||
}
|
||||
if got, want := c.Checksum(), tc.want; got != want {
|
||||
t.Errorf("c.Checksum() = %d, want %d", got, want)
|
||||
}
|
||||
if got, want := Checksum(all.Bytes(), 0 /* initial */), tc.want; got != want {
|
||||
t.Errorf("Checksum(flatten tc.data) = %d, want %d", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChecksum(t *testing.T) {
|
||||
var bufSizes = []int{0, 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128, 255, 256, 257, 1023, 1024}
|
||||
type testCase struct {
|
||||
buf []byte
|
||||
initial uint16
|
||||
csumOrig uint16
|
||||
csumNew uint16
|
||||
}
|
||||
testCases := make([]testCase, 100000)
|
||||
// Ensure same buffer generation for test consistency.
|
||||
rnd := rand.New(rand.NewSource(42))
|
||||
for i := range testCases {
|
||||
testCases[i].buf = make([]byte, bufSizes[i%len(bufSizes)])
|
||||
testCases[i].initial = uint16(rnd.Intn(65536))
|
||||
rnd.Read(testCases[i].buf)
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
testCases[i].csumOrig = Old(testCases[i].buf, testCases[i].initial)
|
||||
testCases[i].csumNew = Checksum(testCases[i].buf, testCases[i].initial)
|
||||
if got, want := testCases[i].csumNew, testCases[i].csumOrig; got != want {
|
||||
t.Fatalf("new checksum for (buf = %x, initial = %d) does not match old got: %d, want: %d", testCases[i].buf, testCases[i].initial, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChecksum(b *testing.B) {
|
||||
var bufSizes = []int{64, 128, 256, 512, 1024, 1500, 2048, 4096, 8192, 16384, 32767, 32768, 65535, 65536}
|
||||
|
||||
checkSumImpls := []struct {
|
||||
fn func([]byte, uint16) uint16
|
||||
name string
|
||||
}{
|
||||
{Old, fmt.Sprintf("checksum_old")},
|
||||
{Checksum, fmt.Sprintf("checksum")},
|
||||
}
|
||||
|
||||
for _, csumImpl := range checkSumImpls {
|
||||
// Ensure same buffer generation for test consistency.
|
||||
rnd := rand.New(rand.NewSource(42))
|
||||
for _, bufSz := range bufSizes {
|
||||
b.Run(fmt.Sprintf("%s_%d", csumImpl.name, bufSz), func(b *testing.B) {
|
||||
tc := struct {
|
||||
buf []byte
|
||||
initial uint16
|
||||
csum uint16
|
||||
}{
|
||||
buf: make([]byte, bufSz),
|
||||
initial: uint16(rnd.Intn(65536)),
|
||||
}
|
||||
rnd.Read(tc.buf)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tc.csum = csumImpl.fn(tc.buf, tc.initial)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/bufferv2",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/checksum",
|
||||
"//pkg/tcpip/seqnum",
|
||||
"@com_github_google_btree//:go_default_library",
|
||||
],
|
||||
@@ -53,6 +54,7 @@ go_test(
|
||||
"//pkg/bufferv2",
|
||||
"//pkg/rand",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/checksum",
|
||||
"//pkg/tcpip/prependable",
|
||||
"//pkg/tcpip/testutil",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
|
||||
@@ -20,230 +20,23 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
)
|
||||
|
||||
// ChecksumSize is the size of a checksum.
|
||||
//
|
||||
// The checksum is held in a uint16 which is 2 bytes.
|
||||
const ChecksumSize = 2
|
||||
|
||||
// PutChecksum puts the checksum in the provided byte slice.
|
||||
func PutChecksum(b []byte, xsum uint16) {
|
||||
binary.BigEndian.PutUint16(b, xsum)
|
||||
}
|
||||
|
||||
func calculateChecksum(buf []byte, odd bool, initial uint32) (uint16, bool) {
|
||||
v := initial
|
||||
|
||||
if odd {
|
||||
v += uint32(buf[0])
|
||||
buf = buf[1:]
|
||||
}
|
||||
|
||||
l := len(buf)
|
||||
odd = l&1 != 0
|
||||
if odd {
|
||||
l--
|
||||
v += uint32(buf[l]) << 8
|
||||
}
|
||||
|
||||
for i := 0; i < l; i += 2 {
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
}
|
||||
|
||||
return ChecksumCombine(uint16(v), uint16(v>>16)), odd
|
||||
}
|
||||
|
||||
func unrolledCalculateChecksum(buf []byte, odd bool, initial uint32) (uint16, bool) {
|
||||
v := initial
|
||||
|
||||
if odd {
|
||||
v += uint32(buf[0])
|
||||
buf = buf[1:]
|
||||
}
|
||||
|
||||
l := len(buf)
|
||||
odd = l&1 != 0
|
||||
if odd {
|
||||
l--
|
||||
v += uint32(buf[l]) << 8
|
||||
}
|
||||
for (l - 64) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
i += 16
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
i += 16
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
i += 16
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
buf = buf[64:]
|
||||
l = l - 64
|
||||
}
|
||||
if (l - 32) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
i += 16
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
buf = buf[32:]
|
||||
l = l - 32
|
||||
}
|
||||
if (l - 16) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9])
|
||||
v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11])
|
||||
v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13])
|
||||
v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15])
|
||||
buf = buf[16:]
|
||||
l = l - 16
|
||||
}
|
||||
if (l - 8) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5])
|
||||
v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7])
|
||||
buf = buf[8:]
|
||||
l = l - 8
|
||||
}
|
||||
if (l - 4) >= 0 {
|
||||
i := 0
|
||||
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
|
||||
v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3])
|
||||
buf = buf[4:]
|
||||
l = l - 4
|
||||
}
|
||||
|
||||
// At this point since l was even before we started unrolling
|
||||
// there can be only two bytes left to add.
|
||||
if l != 0 {
|
||||
v += (uint32(buf[0]) << 8) + uint32(buf[1])
|
||||
}
|
||||
|
||||
return ChecksumCombine(uint16(v), uint16(v>>16)), odd
|
||||
}
|
||||
|
||||
// ChecksumOld calculates the checksum (as defined in RFC 1071) of the bytes in
|
||||
// the given byte array. This function uses a non-optimized implementation. Its
|
||||
// only retained for reference and to use as a benchmark/test. Most code should
|
||||
// use the header.Checksum function.
|
||||
//
|
||||
// The initial checksum must have been computed on an even number of bytes.
|
||||
func ChecksumOld(buf []byte, initial uint16) uint16 {
|
||||
s, _ := calculateChecksum(buf, false, uint32(initial))
|
||||
return s
|
||||
}
|
||||
|
||||
// Checksum calculates the checksum (as defined in RFC 1071) of the bytes in the
|
||||
// given byte array. This function uses an optimized unrolled version of the
|
||||
// checksum algorithm.
|
||||
//
|
||||
// The initial checksum must have been computed on an even number of bytes.
|
||||
func Checksum(buf []byte, initial uint16) uint16 {
|
||||
s, _ := unrolledCalculateChecksum(buf, false, uint32(initial))
|
||||
return s
|
||||
}
|
||||
|
||||
// ChecksumBuffer calculates the checksum (as defined in RFC 1071) of the
|
||||
// bytes in the given Buffer.
|
||||
//
|
||||
// The initial checksum must have been computed on an even number of bytes.
|
||||
func ChecksumBuffer(buf bufferv2.Buffer, initial uint16) uint16 {
|
||||
var c Checksumer
|
||||
buf.Apply(func(v *bufferv2.View) {
|
||||
c.Add(v.AsSlice())
|
||||
})
|
||||
return ChecksumCombine(initial, c.Checksum())
|
||||
}
|
||||
|
||||
// Checksumer calculates checksum defined in RFC 1071.
|
||||
type Checksumer struct {
|
||||
sum uint16
|
||||
odd bool
|
||||
}
|
||||
|
||||
// Add adds b to checksum.
|
||||
func (c *Checksumer) Add(b []byte) {
|
||||
if len(b) > 0 {
|
||||
c.sum, c.odd = unrolledCalculateChecksum(b, c.odd, uint32(c.sum))
|
||||
}
|
||||
}
|
||||
|
||||
// Checksum returns the latest checksum value.
|
||||
func (c *Checksumer) Checksum() uint16 {
|
||||
return c.sum
|
||||
}
|
||||
|
||||
// ChecksumCombine combines the two uint16 to form their checksum. This is done
|
||||
// by adding them and the carry.
|
||||
//
|
||||
// Note that checksum a must have been computed on an even number of bytes.
|
||||
func ChecksumCombine(a, b uint16) uint16 {
|
||||
v := uint32(a) + uint32(b)
|
||||
return uint16(v + v>>16)
|
||||
}
|
||||
|
||||
// PseudoHeaderChecksum calculates the pseudo-header checksum for the given
|
||||
// destination protocol and network address. Pseudo-headers are needed by
|
||||
// transport layers when calculating their own checksum.
|
||||
func PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, srcAddr tcpip.Address, dstAddr tcpip.Address, totalLen uint16) uint16 {
|
||||
xsum := Checksum([]byte(srcAddr), 0)
|
||||
xsum = Checksum([]byte(dstAddr), xsum)
|
||||
xsum := checksum.Checksum([]byte(srcAddr), 0)
|
||||
xsum = checksum.Checksum([]byte(dstAddr), xsum)
|
||||
|
||||
// Add the length portion of the checksum to the pseudo-checksum.
|
||||
tmp := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(tmp, totalLen)
|
||||
xsum = Checksum(tmp, xsum)
|
||||
xsum = checksum.Checksum(tmp, xsum)
|
||||
|
||||
return Checksum([]byte{0, uint8(protocol)}, xsum)
|
||||
return checksum.Checksum([]byte{0, uint8(protocol)}, xsum)
|
||||
}
|
||||
|
||||
// checksumUpdate2ByteAlignedUint16 updates a uint16 value in a calculated
|
||||
@@ -264,7 +57,7 @@ func checksumUpdate2ByteAlignedUint16(xsum, old, new uint16) uint16 {
|
||||
// checksum C, the new checksum C' is:
|
||||
//
|
||||
// C' = C + (-m) + m' = C + (m' - m)
|
||||
return ChecksumCombine(xsum, ChecksumCombine(new, ^old))
|
||||
return checksum.Combine(xsum, checksum.Combine(new, ^old))
|
||||
}
|
||||
|
||||
// checksumUpdate2ByteAlignedAddress updates an address in a calculated
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package header_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
@@ -25,140 +24,10 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
)
|
||||
|
||||
func TestChecksumer(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
data [][]byte
|
||||
want uint16
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "OneOddView",
|
||||
data: [][]byte{
|
||||
{1, 9, 0, 5, 4},
|
||||
},
|
||||
want: 1294,
|
||||
},
|
||||
{
|
||||
name: "TwoOddViews",
|
||||
data: [][]byte{
|
||||
{1, 9, 0, 5, 4},
|
||||
{4, 3, 7, 1, 2, 123},
|
||||
},
|
||||
want: 33819,
|
||||
},
|
||||
{
|
||||
name: "OneEvenView",
|
||||
data: [][]byte{
|
||||
{1, 9, 0, 5},
|
||||
},
|
||||
want: 270,
|
||||
},
|
||||
{
|
||||
name: "TwoEvenViews",
|
||||
data: [][]byte{
|
||||
[]byte{98, 1, 9, 0},
|
||||
[]byte{9, 0, 5, 4},
|
||||
},
|
||||
want: 30981,
|
||||
},
|
||||
{
|
||||
name: "ThreeViews",
|
||||
data: [][]byte{
|
||||
{77, 11, 33, 0, 55, 44},
|
||||
{98, 1, 9, 0, 5, 4},
|
||||
{4, 3, 7, 1, 2, 123, 99},
|
||||
},
|
||||
want: 34236,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var all bytes.Buffer
|
||||
var c header.Checksumer
|
||||
for _, b := range tc.data {
|
||||
c.Add(b)
|
||||
// Append to the buffer. We will check the checksum as a whole later.
|
||||
if _, err := all.Write(b); err != nil {
|
||||
t.Fatalf("all.Write(b) = _, %s; want _, nil", err)
|
||||
}
|
||||
}
|
||||
if got, want := c.Checksum(), tc.want; got != want {
|
||||
t.Errorf("c.Checksum() = %d, want %d", got, want)
|
||||
}
|
||||
if got, want := header.Checksum(all.Bytes(), 0 /* initial */), tc.want; got != want {
|
||||
t.Errorf("Checksum(flatten tc.data) = %d, want %d", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChecksum(t *testing.T) {
|
||||
var bufSizes = []int{0, 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128, 255, 256, 257, 1023, 1024}
|
||||
type testCase struct {
|
||||
buf []byte
|
||||
initial uint16
|
||||
csumOrig uint16
|
||||
csumNew uint16
|
||||
}
|
||||
testCases := make([]testCase, 100000)
|
||||
// Ensure same buffer generation for test consistency.
|
||||
rnd := rand.New(rand.NewSource(42))
|
||||
for i := range testCases {
|
||||
testCases[i].buf = make([]byte, bufSizes[i%len(bufSizes)])
|
||||
testCases[i].initial = uint16(rnd.Intn(65536))
|
||||
rnd.Read(testCases[i].buf)
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
testCases[i].csumOrig = header.ChecksumOld(testCases[i].buf, testCases[i].initial)
|
||||
testCases[i].csumNew = header.Checksum(testCases[i].buf, testCases[i].initial)
|
||||
if got, want := testCases[i].csumNew, testCases[i].csumOrig; got != want {
|
||||
t.Fatalf("new checksum for (buf = %x, initial = %d) does not match old got: %d, want: %d", testCases[i].buf, testCases[i].initial, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChecksum(b *testing.B) {
|
||||
var bufSizes = []int{64, 128, 256, 512, 1024, 1500, 2048, 4096, 8192, 16384, 32767, 32768, 65535, 65536}
|
||||
|
||||
checkSumImpls := []struct {
|
||||
fn func([]byte, uint16) uint16
|
||||
name string
|
||||
}{
|
||||
{header.ChecksumOld, fmt.Sprintf("checksum_old")},
|
||||
{header.Checksum, fmt.Sprintf("checksum")},
|
||||
}
|
||||
|
||||
for _, csumImpl := range checkSumImpls {
|
||||
// Ensure same buffer generation for test consistency.
|
||||
rnd := rand.New(rand.NewSource(42))
|
||||
for _, bufSz := range bufSizes {
|
||||
b.Run(fmt.Sprintf("%s_%d", csumImpl.name, bufSz), func(b *testing.B) {
|
||||
tc := struct {
|
||||
buf []byte
|
||||
initial uint16
|
||||
csum uint16
|
||||
}{
|
||||
buf: make([]byte, bufSz),
|
||||
initial: uint16(rnd.Intn(65536)),
|
||||
}
|
||||
rnd.Read(tc.buf)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tc.csum = csumImpl.fn(tc.buf, tc.initial)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testICMPChecksum(t *testing.T, headerChecksum func() uint16, icmpChecksum func() uint16, want uint16, pktStr string) {
|
||||
// icmpChecksum should not do any modifications of the header to
|
||||
// calculate its checksum. Let's call it from a few go-routines and the
|
||||
@@ -211,12 +80,12 @@ func TestICMPv4Checksum(t *testing.T) {
|
||||
b := bufferv2.MakeWithData(buf[:5])
|
||||
b.Append(bufferv2.NewViewWithData(buf[5:]))
|
||||
|
||||
want := header.Checksum(b.Flatten(), 0)
|
||||
want = ^header.Checksum(h, want)
|
||||
want := checksum.Checksum(b.Flatten(), 0)
|
||||
want = ^checksum.Checksum(h, want)
|
||||
h.SetChecksum(want)
|
||||
|
||||
testICMPChecksum(t, h.Checksum, func() uint16 {
|
||||
return header.ICMPv4Checksum(h, header.ChecksumBuffer(b, 0))
|
||||
return header.ICMPv4Checksum(h, b.Checksum(0))
|
||||
}, want, fmt.Sprintf("header: {% x} data {% x}", h, b.Flatten()))
|
||||
}
|
||||
|
||||
@@ -241,8 +110,8 @@ func TestICMPv6Checksum(t *testing.T) {
|
||||
src := header.IPv6Loopback
|
||||
|
||||
want := header.PseudoHeaderChecksum(header.ICMPv6ProtocolNumber, src, dst, uint16(len(h)+int(b.Size())))
|
||||
want = header.Checksum(b.Flatten(), want)
|
||||
want = ^header.Checksum(h, want)
|
||||
want = checksum.Checksum(b.Flatten(), want)
|
||||
want = ^checksum.Checksum(h, want)
|
||||
h.SetChecksum(want)
|
||||
|
||||
testICMPChecksum(t, h.Checksum, func() uint16 {
|
||||
@@ -250,7 +119,7 @@ func TestICMPv6Checksum(t *testing.T) {
|
||||
Header: h,
|
||||
Src: src,
|
||||
Dst: dst,
|
||||
PayloadCsum: header.ChecksumBuffer(b, 0),
|
||||
PayloadCsum: b.Checksum(0),
|
||||
PayloadLen: int(b.Size()),
|
||||
})
|
||||
}, want, fmt.Sprintf("header: {% x} data {% x}", h, b.Flatten()))
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"encoding/binary"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
)
|
||||
|
||||
// ICMPv4 represents an ICMPv4 header stored in a byte array.
|
||||
@@ -142,8 +143,8 @@ func (b ICMPv4) Checksum() uint16 {
|
||||
}
|
||||
|
||||
// SetChecksum sets the ICMP checksum field.
|
||||
func (b ICMPv4) SetChecksum(checksum uint16) {
|
||||
PutChecksum(b[icmpv4ChecksumOffset:], checksum)
|
||||
func (b ICMPv4) SetChecksum(cs uint16) {
|
||||
checksum.Put(b[icmpv4ChecksumOffset:], cs)
|
||||
}
|
||||
|
||||
// SourcePort implements Transport.SourcePort.
|
||||
@@ -212,8 +213,8 @@ func ICMPv4Checksum(h ICMPv4, payloadCsum uint16) uint16 {
|
||||
xsum := payloadCsum
|
||||
|
||||
// h[2:4] is the checksum itself, skip it to avoid checksumming the checksum.
|
||||
xsum = Checksum(h[:2], xsum)
|
||||
xsum = Checksum(h[4:], xsum)
|
||||
xsum = checksum.Checksum(h[:2], xsum)
|
||||
xsum = checksum.Checksum(h[4:], xsum)
|
||||
|
||||
return ^xsum
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"encoding/binary"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
)
|
||||
|
||||
// ICMPv6 represents an ICMPv6 header stored in a byte array.
|
||||
@@ -198,8 +199,8 @@ func (b ICMPv6) Checksum() uint16 {
|
||||
}
|
||||
|
||||
// SetChecksum sets the ICMP checksum field.
|
||||
func (b ICMPv6) SetChecksum(checksum uint16) {
|
||||
PutChecksum(b[ICMPv6ChecksumOffset:], checksum)
|
||||
func (b ICMPv6) SetChecksum(cs uint16) {
|
||||
checksum.Put(b[ICMPv6ChecksumOffset:], cs)
|
||||
}
|
||||
|
||||
// SourcePort implements Transport.SourcePort.
|
||||
@@ -283,11 +284,11 @@ func ICMPv6Checksum(params ICMPv6ChecksumParams) uint16 {
|
||||
h := params.Header
|
||||
|
||||
xsum := PseudoHeaderChecksum(ICMPv6ProtocolNumber, params.Src, params.Dst, uint16(len(h)+params.PayloadLen))
|
||||
xsum = ChecksumCombine(xsum, params.PayloadCsum)
|
||||
xsum = checksum.Combine(xsum, params.PayloadCsum)
|
||||
|
||||
// h[2:4] is the checksum itself, skip it to avoid checksumming the checksum.
|
||||
xsum = Checksum(h[:2], xsum)
|
||||
xsum = Checksum(h[4:], xsum)
|
||||
xsum = checksum.Checksum(h[:2], xsum)
|
||||
xsum = checksum.Checksum(h[4:], xsum)
|
||||
|
||||
return ^xsum
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
)
|
||||
|
||||
// IGMP represents an IGMP header stored in a byte array.
|
||||
@@ -169,7 +170,7 @@ func IGMPCalculateChecksum(h IGMP) uint16 {
|
||||
// the checksum and replace it afterwards.
|
||||
existingXsum := h.Checksum()
|
||||
h.SetChecksum(0)
|
||||
xsum := ^Checksum(h, 0)
|
||||
xsum := ^checksum.Checksum(h, 0)
|
||||
h.SetChecksum(existingXsum)
|
||||
return xsum
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/testutil"
|
||||
)
|
||||
@@ -94,11 +95,11 @@ func TestIGMPChecksum(t *testing.T) {
|
||||
// to avoid checksumming the checksum.
|
||||
initialChecksum := igmpHeader.Checksum()
|
||||
igmpHeader.SetChecksum(0)
|
||||
checksum := ^header.Checksum(b, 0)
|
||||
xsum := ^checksum.Checksum(b, 0)
|
||||
igmpHeader.SetChecksum(initialChecksum)
|
||||
|
||||
if got := header.IGMPCalculateChecksum(igmpHeader); got != checksum {
|
||||
t.Errorf("got IGMPCalculateChecksum = %x, want %x", got, checksum)
|
||||
if got := header.IGMPCalculateChecksum(igmpHeader); got != xsum {
|
||||
t.Errorf("got IGMPCalculateChecksum = %x, want %x", got, xsum)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
)
|
||||
|
||||
// RFC 971 defines the fields of the IPv4 header on page 11 using the following
|
||||
@@ -50,7 +51,7 @@ const (
|
||||
flagsFO = 6
|
||||
ttl = 8
|
||||
protocol = 9
|
||||
checksum = 10
|
||||
xsum = 10
|
||||
srcAddr = 12
|
||||
dstAddr = 16
|
||||
options = 20
|
||||
@@ -301,7 +302,7 @@ func (b IPv4) TotalLength() uint16 {
|
||||
|
||||
// Checksum returns the checksum field of the IPv4 header.
|
||||
func (b IPv4) Checksum() uint16 {
|
||||
return binary.BigEndian.Uint16(b[checksum:])
|
||||
return binary.BigEndian.Uint16(b[xsum:])
|
||||
}
|
||||
|
||||
// SourceAddress returns the "source address" field of the IPv4 header.
|
||||
@@ -382,7 +383,7 @@ func (b IPv4) SetTotalLength(totalLength uint16) {
|
||||
|
||||
// SetChecksum sets the checksum field of the IPv4 header.
|
||||
func (b IPv4) SetChecksum(v uint16) {
|
||||
PutChecksum(b[checksum:], v)
|
||||
checksum.Put(b[xsum:], v)
|
||||
}
|
||||
|
||||
// SetFlagsFragmentOffset sets the "flags" and "fragment offset" fields of the
|
||||
@@ -410,7 +411,7 @@ func (b IPv4) SetDestinationAddress(addr tcpip.Address) {
|
||||
|
||||
// CalculateChecksum calculates the checksum of the IPv4 header.
|
||||
func (b IPv4) CalculateChecksum() uint16 {
|
||||
return Checksum(b[:b.HeaderLength()], 0)
|
||||
return checksum.Checksum(b[:b.HeaderLength()], 0)
|
||||
}
|
||||
|
||||
// Encode encodes all the fields of the IPv4 header.
|
||||
@@ -444,8 +445,8 @@ func (b IPv4) Encode(i *IPv4Fields) {
|
||||
// packets are produced.
|
||||
func (b IPv4) EncodePartial(partialChecksum, totalLength uint16) {
|
||||
b.SetTotalLength(totalLength)
|
||||
checksum := Checksum(b[IPv4TotalLenOffset:IPv4TotalLenOffset+2], partialChecksum)
|
||||
b.SetChecksum(^checksum)
|
||||
xsum := checksum.Checksum(b[IPv4TotalLenOffset:IPv4TotalLenOffset+2], partialChecksum)
|
||||
b.SetChecksum(^xsum)
|
||||
}
|
||||
|
||||
// IsValid performs basic validation on the packet.
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"github.com/google/btree"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
|
||||
)
|
||||
|
||||
@@ -300,8 +301,8 @@ func (b TCP) SetDestinationPort(port uint16) {
|
||||
}
|
||||
|
||||
// SetChecksum sets the checksum field of the TCP header.
|
||||
func (b TCP) SetChecksum(checksum uint16) {
|
||||
PutChecksum(b[TCPChecksumOffset:], checksum)
|
||||
func (b TCP) SetChecksum(xsum uint16) {
|
||||
checksum.Put(b[TCPChecksumOffset:], xsum)
|
||||
}
|
||||
|
||||
// SetDataOffset sets the data offset field of the TCP header. headerLen should
|
||||
@@ -340,13 +341,13 @@ func (b TCP) SetUrgentPointer(urgentPointer uint16) {
|
||||
// and the checksum of the segment data.
|
||||
func (b TCP) CalculateChecksum(partialChecksum uint16) uint16 {
|
||||
// Calculate the rest of the checksum.
|
||||
return Checksum(b[:b.DataOffset()], partialChecksum)
|
||||
return checksum.Checksum(b[:b.DataOffset()], partialChecksum)
|
||||
}
|
||||
|
||||
// IsChecksumValid returns true iff the TCP header's checksum is valid.
|
||||
func (b TCP) IsChecksumValid(src, dst tcpip.Address, payloadChecksum, payloadLength uint16) bool {
|
||||
xsum := PseudoHeaderChecksum(TCPProtocolNumber, src, dst, uint16(b.DataOffset())+payloadLength)
|
||||
xsum = ChecksumCombine(xsum, payloadChecksum)
|
||||
xsum = checksum.Combine(xsum, payloadChecksum)
|
||||
return b.CalculateChecksum(xsum) == 0xffff
|
||||
}
|
||||
|
||||
@@ -389,17 +390,17 @@ func (b TCP) EncodePartial(partialChecksum, length uint16, seqnum, acknum uint32
|
||||
tmp := make([]byte, 4)
|
||||
binary.BigEndian.PutUint16(tmp, length)
|
||||
binary.BigEndian.PutUint16(tmp[2:], uint16(flags))
|
||||
checksum := Checksum(tmp, partialChecksum)
|
||||
xsum := checksum.Checksum(tmp, partialChecksum)
|
||||
|
||||
// Encode the passed-in fields.
|
||||
b.encodeSubset(seqnum, acknum, flags, rcvwnd)
|
||||
|
||||
// Add the contributions of the passed-in fields to the checksum.
|
||||
checksum = Checksum(b[TCPSeqNumOffset:TCPSeqNumOffset+8], checksum)
|
||||
checksum = Checksum(b[TCPWinSizeOffset:TCPWinSizeOffset+2], checksum)
|
||||
xsum = checksum.Checksum(b[TCPSeqNumOffset:TCPSeqNumOffset+8], xsum)
|
||||
xsum = checksum.Checksum(b[TCPWinSizeOffset:TCPWinSizeOffset+2], xsum)
|
||||
|
||||
// Encode the checksum.
|
||||
b.SetChecksum(^checksum)
|
||||
b.SetChecksum(^xsum)
|
||||
}
|
||||
|
||||
// SetSourcePortWithChecksumUpdate implements ChecksummableTransport.
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"math"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -100,8 +101,8 @@ func (b UDP) SetDestinationPort(port uint16) {
|
||||
}
|
||||
|
||||
// SetChecksum sets the "checksum" field of the UDP header.
|
||||
func (b UDP) SetChecksum(checksum uint16) {
|
||||
PutChecksum(b[udpChecksum:], checksum)
|
||||
func (b UDP) SetChecksum(xsum uint16) {
|
||||
checksum.Put(b[udpChecksum:], xsum)
|
||||
}
|
||||
|
||||
// SetLength sets the "length" field of the UDP header.
|
||||
@@ -113,13 +114,13 @@ func (b UDP) SetLength(length uint16) {
|
||||
// checksum of the network-layer pseudo-header and the checksum of the payload.
|
||||
func (b UDP) CalculateChecksum(partialChecksum uint16) uint16 {
|
||||
// Calculate the rest of the checksum.
|
||||
return Checksum(b[:UDPMinimumSize], partialChecksum)
|
||||
return checksum.Checksum(b[:UDPMinimumSize], partialChecksum)
|
||||
}
|
||||
|
||||
// IsChecksumValid returns true iff the UDP header's checksum is valid.
|
||||
func (b UDP) IsChecksumValid(src, dst tcpip.Address, payloadChecksum uint16) bool {
|
||||
xsum := PseudoHeaderChecksum(UDPProtocolNumber, dst, src, b.Length())
|
||||
xsum = ChecksumCombine(xsum, payloadChecksum)
|
||||
xsum = checksum.Combine(xsum, payloadChecksum)
|
||||
return b.CalculateChecksum(xsum) == 0xffff
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ go_test(
|
||||
"//pkg/sync",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/checker",
|
||||
"//pkg/tcpip/checksum",
|
||||
"//pkg/tcpip/faketime",
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/link/channel",
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checker"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/loopback"
|
||||
@@ -381,7 +382,7 @@ func TestSourceAddressValidation(t *testing.T) {
|
||||
pkt.SetType(header.ICMPv4Echo)
|
||||
pkt.SetCode(0)
|
||||
pkt.SetChecksum(0)
|
||||
pkt.SetChecksum(^header.Checksum(pkt, 0))
|
||||
pkt.SetChecksum(^checksum.Checksum(pkt, 0))
|
||||
ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
|
||||
ip.Encode(&header.IPv4Fields{
|
||||
TotalLength: uint16(totalLen),
|
||||
@@ -916,8 +917,8 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
}
|
||||
|
||||
icmp.SetChecksum(0)
|
||||
checksum := ^header.Checksum(icmp, 0 /* initial */)
|
||||
icmp.SetChecksum(checksum)
|
||||
xsum := ^checksum.Checksum(icmp, 0 /* initial */)
|
||||
icmp.SetChecksum(xsum)
|
||||
|
||||
// Give packet to IPv4 endpoint, dispatcher will validate that
|
||||
// it's ok.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user