diff --git a/pkg/bufferv2/BUILD b/pkg/bufferv2/BUILD index 7b7a31b8a..9dbc2c6d1 100644 --- a/pkg/bufferv2/BUILD +++ b/pkg/bufferv2/BUILD @@ -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", ], ) diff --git a/pkg/bufferv2/buffer.go b/pkg/bufferv2/buffer.go index 58e378907..a7459a376 100644 --- a/pkg/bufferv2/buffer.go +++ b/pkg/bufferv2/buffer.go @@ -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 diff --git a/pkg/bufferv2/buffer_test.go b/pkg/bufferv2/buffer_test.go index 5448d953a..e16e81e6b 100644 --- a/pkg/bufferv2/buffer_test.go +++ b/pkg/bufferv2/buffer_test.go @@ -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) + } + } +} diff --git a/pkg/tcpip/checker/BUILD b/pkg/tcpip/checker/BUILD index 6e78454fe..07ec245fa 100644 --- a/pkg/tcpip/checker/BUILD +++ b/pkg/tcpip/checker/BUILD @@ -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", diff --git a/pkg/tcpip/checker/checker.go b/pkg/tcpip/checker/checker.go index cb4c79a56..71927fda5 100644 --- a/pkg/tcpip/checker/checker.go +++ b/pkg/tcpip/checker/checker.go @@ -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) diff --git a/pkg/tcpip/checksum/BUILD b/pkg/tcpip/checksum/BUILD new file mode 100644 index 000000000..1572d60a4 --- /dev/null +++ b/pkg/tcpip/checksum/BUILD @@ -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"], +) diff --git a/pkg/tcpip/checksum/checksum.go b/pkg/tcpip/checksum/checksum.go new file mode 100644 index 000000000..d2e019151 --- /dev/null +++ b/pkg/tcpip/checksum/checksum.go @@ -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) +} diff --git a/pkg/tcpip/checksum/checksum_test.go b/pkg/tcpip/checksum/checksum_test.go new file mode 100644 index 000000000..4761f6e93 --- /dev/null +++ b/pkg/tcpip/checksum/checksum_test.go @@ -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) + } + }) + } + } +} diff --git a/pkg/tcpip/header/BUILD b/pkg/tcpip/header/BUILD index 80629c9e7..187aec597 100644 --- a/pkg/tcpip/header/BUILD +++ b/pkg/tcpip/header/BUILD @@ -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", diff --git a/pkg/tcpip/header/checksum.go b/pkg/tcpip/header/checksum.go index 419dbf217..8fc436156 100644 --- a/pkg/tcpip/header/checksum.go +++ b/pkg/tcpip/header/checksum.go @@ -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 diff --git a/pkg/tcpip/header/checksum_test.go b/pkg/tcpip/header/checksum_test.go index 0128d6de8..41dc80181 100644 --- a/pkg/tcpip/header/checksum_test.go +++ b/pkg/tcpip/header/checksum_test.go @@ -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())) diff --git a/pkg/tcpip/header/icmpv4.go b/pkg/tcpip/header/icmpv4.go index 85410dbd2..dd385b455 100644 --- a/pkg/tcpip/header/icmpv4.go +++ b/pkg/tcpip/header/icmpv4.go @@ -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 } diff --git a/pkg/tcpip/header/icmpv6.go b/pkg/tcpip/header/icmpv6.go index 26b27ee07..d4b24f81b 100644 --- a/pkg/tcpip/header/icmpv6.go +++ b/pkg/tcpip/header/icmpv6.go @@ -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 } diff --git a/pkg/tcpip/header/igmp.go b/pkg/tcpip/header/igmp.go index af5b5a3d6..94c057f24 100644 --- a/pkg/tcpip/header/igmp.go +++ b/pkg/tcpip/header/igmp.go @@ -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 } diff --git a/pkg/tcpip/header/igmp_test.go b/pkg/tcpip/header/igmp_test.go index 575604928..229eb477a 100644 --- a/pkg/tcpip/header/igmp_test.go +++ b/pkg/tcpip/header/igmp_test.go @@ -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) } } diff --git a/pkg/tcpip/header/ipv4.go b/pkg/tcpip/header/ipv4.go index 6c6ecd1ff..16a63a46d 100644 --- a/pkg/tcpip/header/ipv4.go +++ b/pkg/tcpip/header/ipv4.go @@ -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. diff --git a/pkg/tcpip/header/tcp.go b/pkg/tcpip/header/tcp.go index ed4952319..2d38928ce 100644 --- a/pkg/tcpip/header/tcp.go +++ b/pkg/tcpip/header/tcp.go @@ -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. diff --git a/pkg/tcpip/header/udp.go b/pkg/tcpip/header/udp.go index cdd76acdb..036838dbb 100644 --- a/pkg/tcpip/header/udp.go +++ b/pkg/tcpip/header/udp.go @@ -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 } diff --git a/pkg/tcpip/network/BUILD b/pkg/tcpip/network/BUILD index aebd991fc..db36a08bd 100644 --- a/pkg/tcpip/network/BUILD +++ b/pkg/tcpip/network/BUILD @@ -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", diff --git a/pkg/tcpip/network/ip_test.go b/pkg/tcpip/network/ip_test.go index 0215c61af..915b32d4a 100644 --- a/pkg/tcpip/network/ip_test.go +++ b/pkg/tcpip/network/ip_test.go @@ -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. diff --git a/pkg/tcpip/network/ipv4/BUILD b/pkg/tcpip/network/ipv4/BUILD index 4515d2154..d69c60df2 100644 --- a/pkg/tcpip/network/ipv4/BUILD +++ b/pkg/tcpip/network/ipv4/BUILD @@ -16,6 +16,7 @@ go_library( "//pkg/bufferv2", "//pkg/sync", "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/header/parse", "//pkg/tcpip/network/hash", @@ -41,6 +42,7 @@ go_test( "//pkg/sync", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/faketime", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", diff --git a/pkg/tcpip/network/ipv4/icmp.go b/pkg/tcpip/network/ipv4/icmp.go index e26079d68..f71c00d76 100644 --- a/pkg/tcpip/network/ipv4/icmp.go +++ b/pkg/tcpip/network/ipv4/icmp.go @@ -19,6 +19,7 @@ import ( "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/header/parse" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -183,7 +184,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { } // Only do in-stack processing if the checksum is correct. - if header.Checksum(h, pkt.Data().AsRange().Checksum()) != 0xffff { + if checksum.Checksum(h, pkt.Data().Checksum()) != 0xffff { received.invalid.Increment() // It's possible that a raw socket expects to receive this regardless // of checksum errors. If it's an echo request we know it's safe because @@ -323,7 +324,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { replyICMPHdr := header.ICMPv4(replyData.AsSlice()) replyICMPHdr.SetType(header.ICMPv4EchoReply) replyICMPHdr.SetChecksum(0) - replyICMPHdr.SetChecksum(^header.Checksum(replyData.AsSlice(), 0)) + replyICMPHdr.SetChecksum(^checksum.Checksum(replyData.AsSlice(), 0)) replyBuf := bufferv2.MakeWithView(replyIPHdrView) replyBuf.Append(replyData.Clone()) @@ -665,7 +666,7 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv icmpHdr.SetCode(icmpCode) icmpHdr.SetType(icmpType) icmpHdr.SetPointer(pointer) - icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data().AsRange().Checksum())) + icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data().Checksum())) if err := route.WritePacket( stack.NetworkHeaderParams{ diff --git a/pkg/tcpip/network/ipv4/igmp.go b/pkg/tcpip/network/ipv4/igmp.go index 55dfe7761..3671c5763 100644 --- a/pkg/tcpip/network/ipv4/igmp.go +++ b/pkg/tcpip/network/ipv4/igmp.go @@ -219,7 +219,7 @@ func (igmp *igmpState) handleIGMP(pkt *stack.PacketBuffer, hasRouterAlertOption // same set of octets, including the checksum field. If the result // is all 1 bits (-0 in 1's complement arithmetic), the check // succeeds. - if pkt.Data().AsRange().Checksum() != 0xFFFF { + if pkt.Data().Checksum() != 0xFFFF { received.checksumErrors.Increment() return } diff --git a/pkg/tcpip/network/ipv4/ipv4_test.go b/pkg/tcpip/network/ipv4/ipv4_test.go index 15529ff06..585322832 100644 --- a/pkg/tcpip/network/ipv4/ipv4_test.go +++ b/pkg/tcpip/network/ipv4/ipv4_test.go @@ -31,6 +31,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/faketime" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/channel" @@ -268,7 +269,7 @@ func newICMPEchoPacket(t *testing.T, srcAddr, dstAddr tcpip.Address, ttl uint8, icmpH.SetType(header.ICMPv4Echo) icmpH.SetCode(header.ICMPv4UnusedCode) icmpH.SetChecksum(0) - icmpH.SetChecksum(^header.Checksum(icmpH, 0)) + icmpH.SetChecksum(^checksum.Checksum(icmpH, 0)) ip := header.IPv4(hdr.Prepend(ipHeaderLength)) ip.Encode(&header.IPv4Fields{ TotalLength: uint16(totalLength), @@ -1778,7 +1779,7 @@ func TestIPv4Sanity(t *testing.T) { icmpH.SetType(header.ICMPv4Echo) icmpH.SetCode(header.ICMPv4UnusedCode) icmpH.SetChecksum(0) - icmpH.SetChecksum(^header.Checksum(icmpH, 0)) + icmpH.SetChecksum(^checksum.Checksum(icmpH, 0)) ip := header.IPv4(hdr.Prepend(ipHeaderLength)) if test.maxTotalLength < totalLen { totalLen = test.maxTotalLength @@ -2842,7 +2843,7 @@ func TestReceiveFragments(t *testing.T) { }) copy(u.Payload(), payload) sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(udpLength)) - sum = header.Checksum(payload, sum) + sum = checksum.Checksum(payload, sum) u.SetChecksum(^u.CalculateChecksum(sum)) return hdr.View() } @@ -3553,7 +3554,7 @@ func TestPacketQueuing(t *testing.T) { Length: header.UDPMinimumSize, }) sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv4Addr.AddressWithPrefix.Address, host1IPv4Addr.AddressWithPrefix.Address, header.UDPMinimumSize) - sum = header.Checksum(nil, sum) + sum = checksum.Checksum(nil, sum) u.SetChecksum(^u.CalculateChecksum(sum)) ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) ip.Encode(&header.IPv4Fields{ @@ -3602,7 +3603,7 @@ func TestPacketQueuing(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), @@ -3905,7 +3906,7 @@ func TestIcmpRateLimit(t *testing.T) { icmpH.SetType(header.ICMPv4Echo) icmpH.SetCode(header.ICMPv4UnusedCode) icmpH.SetChecksum(0) - icmpH.SetChecksum(^header.Checksum(icmpH, 0)) + icmpH.SetChecksum(^checksum.Checksum(icmpH, 0)) ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) ip.Encode(&header.IPv4Fields{ TotalLength: uint16(totalLength), diff --git a/pkg/tcpip/network/ipv6/BUILD b/pkg/tcpip/network/ipv6/BUILD index 793ba9f63..b25e283c4 100644 --- a/pkg/tcpip/network/ipv6/BUILD +++ b/pkg/tcpip/network/ipv6/BUILD @@ -44,6 +44,7 @@ go_test( "//pkg/refsvfs2", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/faketime", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", diff --git a/pkg/tcpip/network/ipv6/icmp.go b/pkg/tcpip/network/ipv6/icmp.go index c55d46f70..c19d6bf81 100644 --- a/pkg/tcpip/network/ipv6/icmp.go +++ b/pkg/tcpip/network/ipv6/icmp.go @@ -300,7 +300,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, r dstAddr := iph.DestinationAddress() // Validate ICMPv6 checksum before processing the packet. - payload := pkt.Data().AsRange() + payload := pkt.Data() if got, want := h.Checksum(), header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ Header: h, Src: srcAddr, @@ -682,13 +682,13 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, r replyPkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber copy(icmp, h) icmp.SetType(header.ICMPv6EchoReply) - dataRange := replyPkt.Data().AsRange() + replyData := replyPkt.Data() icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ Header: icmp, Src: r.LocalAddress(), Dst: r.RemoteAddress(), - PayloadCsum: dataRange.Checksum(), - PayloadLen: dataRange.Size(), + PayloadCsum: replyData.Checksum(), + PayloadLen: replyData.Size(), })) replyTClass, _ := iph.TOS() if err := r.WritePacket(stack.NetworkHeaderParams{ @@ -1183,13 +1183,13 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv icmpHdr.SetCode(icmpCode) icmpHdr.SetTypeSpecific(typeSpecific) - dataRange := newPkt.Data().AsRange() + pktData := newPkt.Data() icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ Header: icmpHdr, Src: route.LocalAddress(), Dst: route.RemoteAddress(), - PayloadCsum: dataRange.Checksum(), - PayloadLen: dataRange.Size(), + PayloadCsum: pktData.Checksum(), + PayloadLen: pktData.Size(), })) if err := route.WritePacket( stack.NetworkHeaderParams{ diff --git a/pkg/tcpip/network/ipv6/icmp_test.go b/pkg/tcpip/network/ipv6/icmp_test.go index 417b2c9a9..a5a0ed20a 100644 --- a/pkg/tcpip/network/ipv6/icmp_test.go +++ b/pkg/tcpip/network/ipv6/icmp_test.go @@ -27,6 +27,7 @@ import ( "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/faketime" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/channel" @@ -367,7 +368,7 @@ func TestICMPCounts(t *testing.T) { Header: icmp[:typ.size], Src: lladdr0, Dst: lladdr1, - PayloadCsum: header.Checksum(typ.extraData, 0 /* initial */), + PayloadCsum: checksum.Checksum(typ.extraData, 0 /* initial */), PayloadLen: len(typ.extraData), })) handleICMPInIPv6(ep, lladdr1, lladdr0, icmp, typ.hopLimit, typ.includeRouterAlert) @@ -1158,7 +1159,7 @@ func TestICMPChecksumValidationWithPayloadMultipleViews(t *testing.T) { ) } - handleIPv6Payload := func(typ header.ICMPv6Type, size, payloadSize int, payloadFn func([]byte), checksum bool) { + handleIPv6Payload := func(typ header.ICMPv6Type, size, payloadSize int, payloadFn func([]byte), xsum bool) { hdr := prependable.New(header.IPv6MinimumSize + size) icmpHdr := header.ICMPv6(hdr.Prepend(size)) icmpHdr.SetType(typ) @@ -1166,12 +1167,12 @@ func TestICMPChecksumValidationWithPayloadMultipleViews(t *testing.T) { payload := make([]byte, payloadSize) payloadFn(payload) - if checksum { + if xsum { icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ Header: icmpHdr, Src: lladdr1, Dst: lladdr0, - PayloadCsum: header.Checksum(payload, 0 /* initial */), + PayloadCsum: checksum.Checksum(payload, 0 /* initial */), PayloadLen: len(payload), })) } @@ -1405,7 +1406,7 @@ func TestPacketQueing(t *testing.T) { Length: header.UDPMinimumSize, }) sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv6Addr.AddressWithPrefix.Address, host1IPv6Addr.AddressWithPrefix.Address, header.UDPMinimumSize) - sum = header.Checksum(nil, sum) + sum = checksum.Checksum(nil, sum) u.SetChecksum(^u.CalculateChecksum(sum)) payloadLength := hdr.UsedLength() ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) diff --git a/pkg/tcpip/network/ipv6/ipv6_test.go b/pkg/tcpip/network/ipv6/ipv6_test.go index 97d2916c8..8df942d89 100644 --- a/pkg/tcpip/network/ipv6/ipv6_test.go +++ b/pkg/tcpip/network/ipv6/ipv6_test.go @@ -28,6 +28,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "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" iptestutil "gvisor.dev/gvisor/pkg/tcpip/network/internal/testutil" @@ -139,7 +140,7 @@ func testReceiveUDP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, header.UDPMinimumSize) // UDP checksum - sum = header.Checksum(nil, sum) + sum = checksum.Checksum(nil, sum) u.SetChecksum(^u.CalculateChecksum(sum)) payloadLength := hdr.UsedLength() @@ -980,7 +981,7 @@ func TestReceiveIPv6ExtHdrs(t *testing.T) { } sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, addr1, dstAddr, uint16(udpLength)) - sum = header.Checksum(udpPayload, sum) + sum = checksum.Checksum(udpPayload, sum) u.SetChecksum(^u.CalculateChecksum(sum)) // Copy extension header bytes between the UDP message and the IPv6 @@ -1140,7 +1141,7 @@ func TestReceiveIPv6Fragments(t *testing.T) { }) copy(u.Payload(), payload) sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(udpLength)) - sum = header.Checksum(payload, sum) + sum = checksum.Checksum(payload, sum) u.SetChecksum(^u.CalculateChecksum(sum)) return hdr.View() } @@ -3694,7 +3695,7 @@ func TestIcmpRateLimit(t *testing.T) { // Calculate the UDP checksum and set it. sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv6Addr.AddressWithPrefix.Address, host1IPv6Addr.AddressWithPrefix.Address, header.UDPMinimumSize) - sum = header.Checksum(nil, sum) + sum = checksum.Checksum(nil, sum) udpH.SetChecksum(^udpH.CalculateChecksum(sum)) payloadLength := hdr.UsedLength() diff --git a/pkg/tcpip/network/ipv6/ndp_test.go b/pkg/tcpip/network/ipv6/ndp_test.go index ee1b9ffba..fa29d1b2e 100644 --- a/pkg/tcpip/network/ipv6/ndp_test.go +++ b/pkg/tcpip/network/ipv6/ndp_test.go @@ -25,6 +25,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/faketime" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/channel" @@ -883,7 +884,7 @@ func TestNDPValidation(t *testing.T) { Header: icmpH[:typ.size], Src: lladdr0, Dst: lladdr1, - PayloadCsum: header.Checksum(typ.extraData /* initial */, 0), + PayloadCsum: checksum.Checksum(typ.extraData /* initial */, 0), PayloadLen: len(typ.extraData), })) diff --git a/pkg/tcpip/stack/BUILD b/pkg/tcpip/stack/BUILD index 918a62dae..45569b067 100644 --- a/pkg/tcpip/stack/BUILD +++ b/pkg/tcpip/stack/BUILD @@ -82,6 +82,7 @@ go_library( "//pkg/sleep", "//pkg/sync", "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/hash/jenkins", "//pkg/tcpip/header", "//pkg/tcpip/internal/tcp", @@ -112,6 +113,7 @@ go_test( "//pkg/sync", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/faketime", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", diff --git a/pkg/tcpip/stack/conntrack.go b/pkg/tcpip/stack/conntrack.go index 8bc091abf..cbd7956e8 100644 --- a/pkg/tcpip/stack/conntrack.go +++ b/pkg/tcpip/stack/conntrack.go @@ -526,7 +526,7 @@ func (ct *ConnTrack) getConnAndUpdate(pkt *PacketBuffer, skipChecksumValidation case header.TCPProtocolNumber: _, csumValid, ok := header.TCPValid( header.TCP(pkt.TransportHeader().Slice()), - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), tid.srcAddr, tid.dstAddr, @@ -537,7 +537,7 @@ func (ct *ConnTrack) getConnAndUpdate(pkt *PacketBuffer, skipChecksumValidation case header.UDPProtocolNumber: lengthValid, csumValid := header.UDPValid( header.UDP(pkt.TransportHeader().Slice()), - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), pkt.NetworkProtocolNumber, tid.srcAddr, @@ -937,7 +937,7 @@ func (cn *conn) handlePacket(pkt *PacketBuffer, hook Hook, rt *Route) bool { icmp := header.ICMPv4(pkt.TransportHeader().Slice()) // TODO(https://gvisor.dev/issue/6788): Incrementally update ICMP checksum. icmp.SetChecksum(0) - icmp.SetChecksum(header.ICMPv4Checksum(icmp, pkt.Data().AsRange().Checksum())) + icmp.SetChecksum(header.ICMPv4Checksum(icmp, pkt.Data().Checksum())) network := header.IPv4(pkt.NetworkHeader().Slice()) if dnat { @@ -963,7 +963,7 @@ func (cn *conn) handlePacket(pkt *PacketBuffer, hook Hook, rt *Route) bool { Header: icmp, Src: srcAddr, Dst: dstAddr, - PayloadCsum: payload.AsRange().Checksum(), + PayloadCsum: payload.Checksum(), PayloadLen: payload.Size(), })) diff --git a/pkg/tcpip/stack/packet_buffer.go b/pkg/tcpip/stack/packet_buffer.go index f92f5b0a4..eed38448e 100644 --- a/pkg/tcpip/stack/packet_buffer.go +++ b/pkg/tcpip/stack/packet_buffer.go @@ -651,6 +651,11 @@ func (d PacketData) AsRange() Range { } } +// Checksum returns a checksum over the data payload of the packet. +func (d PacketData) Checksum() uint16 { + return d.pk.buf.Checksum(d.pk.dataOffset()) +} + // Range represents a contiguous subportion of a PacketBuffer. type Range struct { pk *PacketBuffer @@ -713,15 +718,6 @@ func (r Range) ToView() *bufferv2.View { return newV } -// Checksum calculates the RFC 1071 checksum for the underlying bytes of r. -func (r Range) Checksum() uint16 { - var c header.Checksumer - r.iterate(func(v *bufferv2.View) { - c.Add(v.AsSlice()) - }) - return c.Checksum() -} - // iterate calls fn for each piece in r. fn is always called with a non-empty // slice. func (r Range) iterate(fn func(*bufferv2.View)) { diff --git a/pkg/tcpip/stack/packet_buffer_test.go b/pkg/tcpip/stack/packet_buffer_test.go index e6e4fd81c..97b7b9de2 100644 --- a/pkg/tcpip/stack/packet_buffer_test.go +++ b/pkg/tcpip/stack/packet_buffer_test.go @@ -19,7 +19,6 @@ import ( "testing" "gvisor.dev/gvisor/pkg/bufferv2" - "gvisor.dev/gvisor/pkg/tcpip/header" ) func TestPacketHeaderPush(t *testing.T) { @@ -670,9 +669,6 @@ func checkRange(t *testing.T, r Range, data []byte) { if got := r.ToSlice(); !bytes.Equal(got, data) { t.Errorf("r.AsSlice() = %x, want %x", got, data) } - if got, want := r.Checksum(), header.Checksum(data, 0 /* initial */); got != want { - t.Errorf("r.Checksum() = %x, want %x", got, want) - } } func buf(pieces ...string) bufferv2.Buffer { diff --git a/pkg/tcpip/stack/transport_demuxer_test.go b/pkg/tcpip/stack/transport_demuxer_test.go index f206c0963..77b123560 100644 --- a/pkg/tcpip/stack/transport_demuxer_test.go +++ b/pkg/tcpip/stack/transport_demuxer_test.go @@ -23,6 +23,7 @@ import ( "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/link/channel" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" @@ -134,7 +135,7 @@ func (c *testContext) sendV4Packet(payload []byte, h *headers, linkEpID tcpip.NI xsum := header.PseudoHeaderChecksum(udp.ProtocolNumber, testSrcAddrV4, testDstAddrV4, uint16(len(u))) // Calculate the UDP checksum and set it. - xsum = header.Checksum(payload, xsum) + xsum = checksum.Checksum(payload, xsum) u.SetChecksum(^u.CalculateChecksum(xsum)) // Inject packet. @@ -171,7 +172,7 @@ func (c *testContext) sendV6Packet(payload []byte, h *headers, linkEpID tcpip.NI xsum := header.PseudoHeaderChecksum(udp.ProtocolNumber, testSrcAddrV6, testDstAddrV6, uint16(len(u))) // Calculate the UDP checksum and set it. - xsum = header.Checksum(payload, xsum) + xsum = checksum.Checksum(payload, xsum) u.SetChecksum(^u.CalculateChecksum(xsum)) // Inject packet. diff --git a/pkg/tcpip/tests/integration/BUILD b/pkg/tcpip/tests/integration/BUILD index 74ab47b5e..df5d6de75 100644 --- a/pkg/tcpip/tests/integration/BUILD +++ b/pkg/tcpip/tests/integration/BUILD @@ -33,6 +33,7 @@ go_test( "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", "//pkg/tcpip/link/loopback", @@ -59,6 +60,7 @@ go_test( "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/faketime", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", @@ -110,6 +112,7 @@ go_test( "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", "//pkg/tcpip/link/loopback", diff --git a/pkg/tcpip/tests/integration/iptables_test.go b/pkg/tcpip/tests/integration/iptables_test.go index bd4f272e0..e200e3a15 100644 --- a/pkg/tcpip/tests/integration/iptables_test.go +++ b/pkg/tcpip/tests/integration/iptables_test.go @@ -24,6 +24,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "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" @@ -388,7 +389,7 @@ func TestIPTableWritePackets(t *testing.T) { Length: header.UDPMinimumSize, }) sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, srcAddr, dstAddr, header.UDPMinimumSize) - sum = header.Checksum(hdr, sum) + sum = checksum.Checksum(hdr, sum) u.SetChecksum(^u.CalculateChecksum(sum)) } @@ -2094,7 +2095,7 @@ func icmpv4Packet(srcAddr, dstAddr tcpip.Address, icmpType header.ICMPv4Type, id icmp.SetType(icmpType) icmp.SetIdent(ident) icmp.SetChecksum(0) - icmp.SetChecksum(^header.Checksum(icmp, 0)) + icmp.SetChecksum(^checksum.Checksum(icmp, 0)) encodeIPv4Header( hdr.Prepend(header.IPv4MinimumSize), hdr.UsedLength(), diff --git a/pkg/tcpip/tests/integration/link_resolution_test.go b/pkg/tcpip/tests/integration/link_resolution_test.go index 754a59541..c9f71caf7 100644 --- a/pkg/tcpip/tests/integration/link_resolution_test.go +++ b/pkg/tcpip/tests/integration/link_resolution_test.go @@ -27,6 +27,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/faketime" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/channel" @@ -969,7 +970,7 @@ func TestWritePacketsLinkResolution(t *testing.T) { Length: length, }) xsum := r.PseudoHeaderChecksum(udp.ProtocolNumber, length) - xsum = header.ChecksumCombine(xsum, pkt.Data().AsRange().Checksum()) + xsum = checksum.Combine(xsum, pkt.Data().Checksum()) udpHdr.SetChecksum(^udpHdr.CalculateChecksum(xsum)) if err := r.WritePacket(params, pkt); err != nil { diff --git a/pkg/tcpip/tests/integration/multicast_broadcast_test.go b/pkg/tcpip/tests/integration/multicast_broadcast_test.go index 399cb3861..0fe229fc6 100644 --- a/pkg/tcpip/tests/integration/multicast_broadcast_test.go +++ b/pkg/tcpip/tests/integration/multicast_broadcast_test.go @@ -22,6 +22,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "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" @@ -187,7 +188,7 @@ func rxIPv4UDP(e *channel.Endpoint, src, dst tcpip.Address, data []byte) { }) copy(u.Payload(), data) sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(payloadLen)) - sum = header.Checksum(data, sum) + sum = checksum.Checksum(data, sum) u.SetChecksum(^u.CalculateChecksum(sum)) ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) @@ -216,7 +217,7 @@ func rxIPv6UDP(e *channel.Endpoint, src, dst tcpip.Address, data []byte) { }) copy(u.Payload(), data) sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(payloadLen)) - sum = header.Checksum(data, sum) + sum = checksum.Checksum(data, sum) u.SetChecksum(^u.CalculateChecksum(sum)) ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) diff --git a/pkg/tcpip/tests/utils/BUILD b/pkg/tcpip/tests/utils/BUILD index 299b59e85..ad3939c72 100644 --- a/pkg/tcpip/tests/utils/BUILD +++ b/pkg/tcpip/tests/utils/BUILD @@ -10,6 +10,7 @@ go_library( deps = [ "//pkg/bufferv2", "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", "//pkg/tcpip/link/ethernet", diff --git a/pkg/tcpip/tests/utils/utils.go b/pkg/tcpip/tests/utils/utils.go index 5f0b9d00c..d83951361 100644 --- a/pkg/tcpip/tests/utils/utils.go +++ b/pkg/tcpip/tests/utils/utils.go @@ -20,6 +20,7 @@ import ( "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/link/channel" "gvisor.dev/gvisor/pkg/tcpip/link/ethernet" @@ -362,7 +363,7 @@ func ICMPv4Echo(src, dst tcpip.Address, ttl uint8, ty header.ICMPv4Type) []byte pkt.SetType(ty) pkt.SetCode(header.ICMPv4UnusedCode) 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), diff --git a/pkg/tcpip/transport/icmp/BUILD b/pkg/tcpip/transport/icmp/BUILD index dbca4db57..0a20fb3a3 100644 --- a/pkg/tcpip/transport/icmp/BUILD +++ b/pkg/tcpip/transport/icmp/BUILD @@ -30,6 +30,7 @@ go_library( "//pkg/sleep", "//pkg/sync", "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/ports", "//pkg/tcpip/stack", @@ -51,6 +52,7 @@ go_test( "//pkg/refsvfs2", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", "//pkg/tcpip/link/sniffer", diff --git a/pkg/tcpip/transport/icmp/endpoint.go b/pkg/tcpip/transport/icmp/endpoint.go index 4d26400f8..8a4825cc3 100644 --- a/pkg/tcpip/transport/icmp/endpoint.go +++ b/pkg/tcpip/transport/icmp/endpoint.go @@ -22,6 +22,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/ports" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -425,7 +426,7 @@ func send4(s *stack.Stack, ctx *network.WriteContext, ident uint16, data *buffer } icmpv4.SetChecksum(0) - icmpv4.SetChecksum(^header.Checksum(icmpv4, header.Checksum(data.AsSlice(), 0))) + icmpv4.SetChecksum(^checksum.Checksum(icmpv4, checksum.Checksum(data.AsSlice(), 0))) pkt.Data().AppendView(data.Clone()) // Because this icmp endpoint is implemented in the transport layer, we can @@ -465,13 +466,13 @@ func send6(s *stack.Stack, ctx *network.WriteContext, ident uint16, data *buffer } pkt.Data().AppendView(data.Clone()) - dataRange := pkt.Data().AsRange() + pktData := pkt.Data() icmpv6.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ Header: icmpv6, Src: src, Dst: dst, - PayloadCsum: dataRange.Checksum(), - PayloadLen: dataRange.Size(), + PayloadCsum: pktData.Checksum(), + PayloadLen: pktData.Size(), })) // Because this icmp endpoint is implemented in the transport layer, we can diff --git a/pkg/tcpip/transport/icmp/icmp_test.go b/pkg/tcpip/transport/icmp/icmp_test.go index cd630e3a6..7d82a00d6 100644 --- a/pkg/tcpip/transport/icmp/icmp_test.go +++ b/pkg/tcpip/transport/icmp/icmp_test.go @@ -23,6 +23,7 @@ import ( "gvisor.dev/gvisor/pkg/refsvfs2" "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/sniffer" @@ -273,7 +274,7 @@ func buildV4EchoReplyPacket(payload []byte, h context.Header4Tuple) ([]byte, []b icmp.SetType(header.ICMPv4EchoReply) icmp.SetCode(header.ICMPv4UnusedCode) icmp.SetIdent(h.Dst.Port) - icmp.SetChecksum(^header.Checksum(icmp, 0)) + icmp.SetChecksum(^checksum.Checksum(icmp, 0)) return buf, icmp } @@ -304,7 +305,7 @@ func buildV6EchoReplyPacket(payload []byte, h context.Header4Tuple) ([]byte, []b Header: icmpv6[:header.ICMPv6EchoMinimumSize], Src: h.Src.Addr, Dst: h.Dst.Addr, - PayloadCsum: header.Checksum(payload, 0), + PayloadCsum: checksum.Checksum(payload, 0), PayloadLen: len(payload), })) diff --git a/pkg/tcpip/transport/raw/BUILD b/pkg/tcpip/transport/raw/BUILD index b9088c45f..4d2eaef5a 100644 --- a/pkg/tcpip/transport/raw/BUILD +++ b/pkg/tcpip/transport/raw/BUILD @@ -30,6 +30,7 @@ go_library( "//pkg/sleep", "//pkg/sync", "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/stack", "//pkg/tcpip/transport", diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go index 4580dd79b..b4dac52b5 100644 --- a/pkg/tcpip/transport/raw/endpoint.go +++ b/pkg/tcpip/transport/raw/endpoint.go @@ -33,6 +33,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/transport" @@ -358,15 +359,15 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp if packetInfo := ctx.PacketInfo(); packetInfo.NetProto == header.IPv6ProtocolNumber && ipv6ChecksumOffset >= 0 { // Make sure we can fit the checksum. - if payload.Size() < int64(ipv6ChecksumOffset+header.ChecksumSize) { + if payload.Size() < int64(ipv6ChecksumOffset+checksum.Size) { return 0, &tcpip.ErrInvalidOptionValue{} } payloadView, _ := payload.PullUp(ipv6ChecksumOffset, int(payload.Size())-ipv6ChecksumOffset) xsum := header.PseudoHeaderChecksum(e.transProto, packetInfo.LocalAddress, packetInfo.RemoteAddress, uint16(payload.Size())) - header.PutChecksum(payloadView.AsSlice(), 0) - xsum = header.ChecksumBuffer(payload, xsum) - header.PutChecksum(payloadView.AsSlice(), ^xsum) + checksum.Put(payloadView.AsSlice(), 0) + xsum = checksum.Combine(payload.Checksum(0), xsum) + checksum.Put(payloadView.AsSlice(), ^xsum) } pkt := ctx.TryNewPacketBuffer(int(ctx.PacketInfo().MaxHeaderLength), payload.Clone()) @@ -516,7 +517,7 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) tcpip.Error { } // Make sure the offset is aligned properly if checksum is requested. - if v > 0 && v%header.ChecksumSize != 0 { + if v > 0 && v%checksum.Size != 0 { return &tcpip.ErrInvalidOptionValue{} } @@ -701,13 +702,13 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { if checksumOffset := e.ipv6ChecksumOffset; checksumOffset >= 0 { bufSize := int(combinedBuf.Size()) - if bufSize < checksumOffset+header.ChecksumSize { + if bufSize < checksumOffset+checksum.Size { // Message too small to fit checksum. return false } xsum := header.PseudoHeaderChecksum(e.transProto, srcAddr, dstAddr, uint16(bufSize)) - xsum = header.ChecksumBuffer(combinedBuf, xsum) + xsum = checksum.Combine(combinedBuf.Checksum(0), xsum) if xsum != 0xFFFF { // Invalid checksum. return false diff --git a/pkg/tcpip/transport/tcp/BUILD b/pkg/tcpip/transport/tcp/BUILD index 792f1c809..d8c1e9e2f 100644 --- a/pkg/tcpip/transport/tcp/BUILD +++ b/pkg/tcpip/transport/tcp/BUILD @@ -78,6 +78,7 @@ go_library( "//pkg/sleep", "//pkg/sync", "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/hash/jenkins", "//pkg/tcpip/header", "//pkg/tcpip/header/parse", diff --git a/pkg/tcpip/transport/tcp/connect.go b/pkg/tcpip/transport/tcp/connect.go index 35fc9da17..7847484db 100644 --- a/pkg/tcpip/transport/tcp/connect.go +++ b/pkg/tcpip/transport/tcp/connect.go @@ -22,6 +22,7 @@ import ( "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/hash/jenkins" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/seqnum" @@ -838,7 +839,7 @@ func buildTCPHdr(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso stac // header and data and get the right sum of the TCP packet. tcp.SetChecksum(xsum) } else if r.RequiresTXTransportChecksum() { - xsum = header.ChecksumCombine(xsum, pkt.Data().AsRange().Checksum()) + xsum = checksum.Combine(xsum, pkt.Data().Checksum()) tcp.SetChecksum(^tcp.CalculateChecksum(xsum)) } } diff --git a/pkg/tcpip/transport/tcp/segment.go b/pkg/tcpip/transport/tcp/segment.go index 5ea9e8a02..40946b319 100644 --- a/pkg/tcpip/transport/tcp/segment.go +++ b/pkg/tcpip/transport/tcp/segment.go @@ -97,7 +97,7 @@ func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *st netHdr := pkt.Network() csum, csumValid, ok := header.TCPValid( hdr, - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), netHdr.SourceAddress(), netHdr.DestinationAddress(), diff --git a/pkg/tcpip/transport/tcp/testing/context/BUILD b/pkg/tcpip/transport/tcp/testing/context/BUILD index 2aa9ccbbc..bdbab2fdc 100644 --- a/pkg/tcpip/transport/tcp/testing/context/BUILD +++ b/pkg/tcpip/transport/tcp/testing/context/BUILD @@ -13,6 +13,7 @@ go_library( "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", "//pkg/tcpip/link/sniffer", diff --git a/pkg/tcpip/transport/tcp/testing/context/context.go b/pkg/tcpip/transport/tcp/testing/context/context.go index d5e1b0926..824924b18 100644 --- a/pkg/tcpip/transport/tcp/testing/context/context.go +++ b/pkg/tcpip/transport/tcp/testing/context/context.go @@ -25,6 +25,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "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/sniffer" @@ -424,8 +425,8 @@ func (c *Context) SendICMPPacket(typ header.ICMPv4Type, code header.ICMPv4Code, copy(icmp[icmpv4VariableHeaderOffset:], p1.AsSlice()) copy(icmp[header.ICMPv4PayloadOffset:], p2.AsSlice()) icmp.SetChecksum(0) - checksum := ^header.Checksum(icmp, 0 /* initial */) - icmp.SetChecksum(checksum) + xsum := ^checksum.Checksum(icmp, 0 /* initial */) + icmp.SetChecksum(xsum) // Inject packet. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ @@ -475,7 +476,7 @@ func (c *Context) BuildSegmentWithAddrs(payload []byte, h *Headers, src, dst tcp xsum := header.PseudoHeaderChecksum(tcp.ProtocolNumber, src, dst, uint16(len(t))) // Calculate the TCP checksum and set it. - xsum = header.Checksum(payload, xsum) + xsum = checksum.Checksum(payload, xsum) t.SetChecksum(^t.CalculateChecksum(xsum)) // Inject packet. @@ -679,7 +680,7 @@ func (c *Context) SendV6PacketWithAddrs(payload []byte, h *Headers, src, dst tcp xsum := header.PseudoHeaderChecksum(tcp.ProtocolNumber, src, dst, uint16(len(t))) // Calculate the TCP checksum and set it. - xsum = header.Checksum(payload, xsum) + xsum = checksum.Checksum(payload, xsum) t.SetChecksum(^t.CalculateChecksum(xsum)) // Inject packet. diff --git a/pkg/tcpip/transport/testing/context/BUILD b/pkg/tcpip/transport/testing/context/BUILD index 911922273..61d781ce9 100644 --- a/pkg/tcpip/transport/testing/context/BUILD +++ b/pkg/tcpip/transport/testing/context/BUILD @@ -17,6 +17,7 @@ go_library( "//pkg/refsvfs2", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/faketime", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", diff --git a/pkg/tcpip/transport/testing/context/flow.go b/pkg/tcpip/transport/testing/context/flow.go index b1269261a..b1189280d 100644 --- a/pkg/tcpip/transport/testing/context/flow.go +++ b/pkg/tcpip/transport/testing/context/flow.go @@ -21,6 +21,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "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/network/ipv4" "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" @@ -372,7 +373,7 @@ func BuildV4UDPPacket(payload []byte, h Header4Tuple, tos, ttl uint8, badChecksu xsum := header.PseudoHeaderChecksum(udp.ProtocolNumber, h.Src.Addr, h.Dst.Addr, uint16(len(u))) // Calculate the UDP checksum and set it. - xsum = header.Checksum(payload, xsum) + xsum = checksum.Checksum(payload, xsum) u.SetChecksum(^u.CalculateChecksum(xsum)) if badChecksum { @@ -419,7 +420,7 @@ func BuildV6UDPPacket(payload []byte, h Header4Tuple, tclass, hoplimit uint8, ba xsum := header.PseudoHeaderChecksum(udp.ProtocolNumber, h.Src.Addr, h.Dst.Addr, uint16(len(u))) // Calculate the UDP checksum and set it. - xsum = header.Checksum(payload, xsum) + xsum = checksum.Checksum(payload, xsum) u.SetChecksum(^u.CalculateChecksum(xsum)) if badChecksum { diff --git a/pkg/tcpip/transport/udp/BUILD b/pkg/tcpip/transport/udp/BUILD index 9cbb03246..61f5db821 100644 --- a/pkg/tcpip/transport/udp/BUILD +++ b/pkg/tcpip/transport/udp/BUILD @@ -31,6 +31,7 @@ go_library( "//pkg/sleep", "//pkg/sync", "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/header/parse", "//pkg/tcpip/ports", @@ -53,6 +54,7 @@ go_test( "//pkg/refsvfs2", "//pkg/tcpip", "//pkg/tcpip/checker", + "//pkg/tcpip/checksum", "//pkg/tcpip/faketime", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", diff --git a/pkg/tcpip/transport/udp/endpoint.go b/pkg/tcpip/transport/udp/endpoint.go index c9a43240f..3bb44ae57 100644 --- a/pkg/tcpip/transport/udp/endpoint.go +++ b/pkg/tcpip/transport/udp/endpoint.go @@ -24,6 +24,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/ports" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -494,9 +495,9 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp // On IPv6, UDP checksum is not optional (RFC2460 Section 8.1). if pktInfo.RequiresTXTransportChecksum && (!e.ops.GetNoChecksum() || pktInfo.NetProto == header.IPv6ProtocolNumber) { - xsum := udp.CalculateChecksum(header.ChecksumCombine( + xsum := udp.CalculateChecksum(checksum.Combine( header.PseudoHeaderChecksum(ProtocolNumber, pktInfo.LocalAddress, pktInfo.RemoteAddress, length), - pkt.Data().AsRange().Checksum(), + pkt.Data().Checksum(), )) // As per RFC 768 page 2, // @@ -907,7 +908,7 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB netHdr := pkt.Network() lengthValid, csumValid := header.UDPValid( hdr, - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), pkt.NetworkProtocolNumber, netHdr.SourceAddress(), diff --git a/pkg/tcpip/transport/udp/protocol.go b/pkg/tcpip/transport/udp/protocol.go index 8b4368908..45b7114e7 100644 --- a/pkg/tcpip/transport/udp/protocol.go +++ b/pkg/tcpip/transport/udp/protocol.go @@ -82,7 +82,7 @@ func (p *protocol) HandleUnknownDestinationPacket(id stack.TransportEndpointID, netHdr := pkt.Network() lengthValid, csumValid := header.UDPValid( hdr, - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), pkt.NetworkProtocolNumber, netHdr.SourceAddress(), diff --git a/pkg/tcpip/transport/udp/udp_test.go b/pkg/tcpip/transport/udp/udp_test.go index 64bab33d9..556c5ff66 100644 --- a/pkg/tcpip/transport/udp/udp_test.go +++ b/pkg/tcpip/transport/udp/udp_test.go @@ -29,6 +29,7 @@ import ( "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/faketime" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/channel" @@ -2232,7 +2233,7 @@ func TestChecksumWithZeroValueOnesComplementSum(t *testing.T) { // Make sure the all ones checksum is valid. hdr := header.IPv6(v.AsSlice()) udp := header.UDP(hdr.Payload()) - if src, dst, payloadXsum := hdr.SourceAddress(), hdr.DestinationAddress(), header.Checksum(udp.Payload(), 0); !udp.IsChecksumValid(src, dst, payloadXsum) { + if src, dst, payloadXsum := hdr.SourceAddress(), hdr.DestinationAddress(), checksum.Checksum(udp.Payload(), 0); !udp.IsChecksumValid(src, dst, payloadXsum) { t.Errorf("got udp.IsChecksumValid(%s, %s, %d) = false, want = true", src, dst, payloadXsum) } } diff --git a/test/packetimpact/testbench/BUILD b/test/packetimpact/testbench/BUILD index 680d928e6..6d249cf3d 100644 --- a/test/packetimpact/testbench/BUILD +++ b/test/packetimpact/testbench/BUILD @@ -21,6 +21,7 @@ go_library( "//pkg/bufferv2", "//pkg/hostarch", "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/seqnum", "//test/packetimpact/proto:posix_server_go_proto", diff --git a/test/packetimpact/testbench/layers.go b/test/packetimpact/testbench/layers.go index 3fc89818f..a3c897399 100644 --- a/test/packetimpact/testbench/layers.go +++ b/test/packetimpact/testbench/layers.go @@ -26,6 +26,7 @@ import ( "go.uber.org/multierr" "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" ) @@ -882,7 +883,7 @@ func (l *ICMPv6) ToBytes() ([]byte, error) { Header: h[:header.ICMPv6PayloadOffset], Src: *ipv6.SrcAddr, Dst: *ipv6.DstAddr, - PayloadCsum: header.Checksum(l.Payload, 0 /* initial */), + PayloadCsum: checksum.Checksum(l.Payload, 0 /* initial */), PayloadLen: len(l.Payload), })) break @@ -998,7 +999,7 @@ func (l *ICMPv4) ToBytes() ([]byte, error) { if l.Checksum != nil { h.SetChecksum(*l.Checksum) } else { - h.SetChecksum(^header.Checksum(h, 0)) + h.SetChecksum(^checksum.Checksum(h, 0)) } return h, nil @@ -1144,7 +1145,7 @@ func layerChecksum(l Layer, protoNumber tcpip.TransportProtocolNumber) (uint16, if err != nil { return 0, err } - xsum = header.ChecksumBuffer(payloadBytes, xsum) + xsum = checksum.Checksum(payloadBytes.Flatten(), xsum) return xsum, nil } diff --git a/test/packetimpact/tests/BUILD b/test/packetimpact/tests/BUILD index a3707e502..e2d6b9808 100644 --- a/test/packetimpact/tests/BUILD +++ b/test/packetimpact/tests/BUILD @@ -280,6 +280,7 @@ packetimpact_testbench( name = "ipv4_fragment_reassembly", srcs = ["ipv4_fragment_reassembly_test.go"], deps = [ + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//test/packetimpact/testbench", "@com_github_google_go_cmp//cmp:go_default_library", @@ -292,6 +293,7 @@ packetimpact_testbench( srcs = ["ipv6_fragment_reassembly_test.go"], deps = [ "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//test/packetimpact/testbench", "@com_github_google_go_cmp//cmp:go_default_library", @@ -304,6 +306,7 @@ packetimpact_testbench( srcs = ["ipv6_fragment_icmp_error_test.go"], deps = [ "//pkg/tcpip", + "//pkg/tcpip/checksum", "//pkg/tcpip/header", "//pkg/tcpip/network/ipv6", "//test/packetimpact/testbench", diff --git a/test/packetimpact/tests/ipv4_fragment_reassembly_test.go b/test/packetimpact/tests/ipv4_fragment_reassembly_test.go index 707f0f1f5..b76796358 100644 --- a/test/packetimpact/tests/ipv4_fragment_reassembly_test.go +++ b/test/packetimpact/tests/ipv4_fragment_reassembly_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/google/go-cmp/cmp" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/test/packetimpact/testbench" ) @@ -117,7 +118,7 @@ func TestIPv4FragmentReassembly(t *testing.T) { if _, err := rand.Read(originalPayload); err != nil { t.Fatalf("rand.Read: %s", err) } - cksum := header.ICMPv4Checksum(icmp, header.Checksum(originalPayload, 0 /* initial */)) + cksum := header.ICMPv4Checksum(icmp, checksum.Checksum(originalPayload, 0 /* initial */)) icmp.SetChecksum(cksum) for _, fragment := range test.fragments { diff --git a/test/packetimpact/tests/ipv6_fragment_icmp_error_test.go b/test/packetimpact/tests/ipv6_fragment_icmp_error_test.go index 4034a128e..8a4683c66 100644 --- a/test/packetimpact/tests/ipv6_fragment_icmp_error_test.go +++ b/test/packetimpact/tests/ipv6_fragment_icmp_error_test.go @@ -21,6 +21,7 @@ import ( "github.com/google/go-cmp/cmp" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" "gvisor.dev/gvisor/test/packetimpact/testbench" @@ -48,7 +49,7 @@ func fragmentedICMPEchoRequest(t *testing.T, n *testbench.DUTTestNet, conn *test Header: icmpv6Header, Src: tcpip.Address(n.LocalIPv6), Dst: tcpip.Address(n.RemoteIPv6), - PayloadCsum: header.Checksum(payload, 0 /* initial */), + PayloadCsum: checksum.Checksum(payload, 0 /* initial */), PayloadLen: len(payload), }) icmpv6Header.SetChecksum(cksum) diff --git a/test/packetimpact/tests/ipv6_fragment_reassembly_test.go b/test/packetimpact/tests/ipv6_fragment_reassembly_test.go index db6195dc9..16897fa68 100644 --- a/test/packetimpact/tests/ipv6_fragment_reassembly_test.go +++ b/test/packetimpact/tests/ipv6_fragment_reassembly_test.go @@ -22,6 +22,7 @@ import ( "github.com/google/go-cmp/cmp" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/test/packetimpact/testbench" ) @@ -124,7 +125,7 @@ func TestIPv6FragmentReassembly(t *testing.T) { Header: icmp, Src: lIP, Dst: rIP, - PayloadCsum: header.Checksum(originalPayload, 0 /* initial */), + PayloadCsum: checksum.Checksum(originalPayload, 0 /* initial */), PayloadLen: len(originalPayload), }) icmp.SetChecksum(cksum)