From 22ca20c0f151fb2e0dad93c2de8657717d28a170 Mon Sep 17 00:00:00 2001 From: Lucas Manning Date: Thu, 8 Sep 2022 15:13:41 -0700 Subject: [PATCH] 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 --- pkg/bufferv2/BUILD | 2 + pkg/bufferv2/buffer.go | 20 ++ pkg/bufferv2/buffer_test.go | 22 ++ pkg/tcpip/checker/BUILD | 1 + pkg/tcpip/checker/checker.go | 5 +- pkg/tcpip/checksum/BUILD | 15 ++ pkg/tcpip/checksum/checksum.go | 216 +++++++++++++++++ pkg/tcpip/checksum/checksum_test.go | 155 +++++++++++++ pkg/tcpip/header/BUILD | 2 + pkg/tcpip/header/checksum.go | 219 +----------------- pkg/tcpip/header/checksum_test.go | 145 +----------- pkg/tcpip/header/icmpv4.go | 9 +- pkg/tcpip/header/icmpv6.go | 11 +- pkg/tcpip/header/igmp.go | 3 +- pkg/tcpip/header/igmp_test.go | 7 +- pkg/tcpip/header/ipv4.go | 13 +- pkg/tcpip/header/tcp.go | 17 +- pkg/tcpip/header/udp.go | 9 +- pkg/tcpip/network/BUILD | 1 + pkg/tcpip/network/ip_test.go | 7 +- pkg/tcpip/network/ipv4/BUILD | 2 + pkg/tcpip/network/ipv4/icmp.go | 7 +- pkg/tcpip/network/ipv4/igmp.go | 2 +- pkg/tcpip/network/ipv4/ipv4_test.go | 13 +- pkg/tcpip/network/ipv6/BUILD | 1 + pkg/tcpip/network/ipv6/icmp.go | 14 +- pkg/tcpip/network/ipv6/icmp_test.go | 11 +- pkg/tcpip/network/ipv6/ipv6_test.go | 9 +- pkg/tcpip/network/ipv6/ndp_test.go | 3 +- pkg/tcpip/stack/BUILD | 2 + pkg/tcpip/stack/conntrack.go | 8 +- pkg/tcpip/stack/packet_buffer.go | 14 +- pkg/tcpip/stack/packet_buffer_test.go | 4 - pkg/tcpip/stack/transport_demuxer_test.go | 5 +- pkg/tcpip/tests/integration/BUILD | 3 + pkg/tcpip/tests/integration/iptables_test.go | 5 +- .../tests/integration/link_resolution_test.go | 3 +- .../integration/multicast_broadcast_test.go | 5 +- pkg/tcpip/tests/utils/BUILD | 1 + pkg/tcpip/tests/utils/utils.go | 3 +- pkg/tcpip/transport/icmp/BUILD | 2 + pkg/tcpip/transport/icmp/endpoint.go | 9 +- pkg/tcpip/transport/icmp/icmp_test.go | 5 +- pkg/tcpip/transport/raw/BUILD | 1 + pkg/tcpip/transport/raw/endpoint.go | 15 +- pkg/tcpip/transport/tcp/BUILD | 1 + pkg/tcpip/transport/tcp/connect.go | 3 +- pkg/tcpip/transport/tcp/segment.go | 2 +- pkg/tcpip/transport/tcp/testing/context/BUILD | 1 + .../transport/tcp/testing/context/context.go | 9 +- pkg/tcpip/transport/testing/context/BUILD | 1 + pkg/tcpip/transport/testing/context/flow.go | 5 +- pkg/tcpip/transport/udp/BUILD | 2 + pkg/tcpip/transport/udp/endpoint.go | 7 +- pkg/tcpip/transport/udp/protocol.go | 2 +- pkg/tcpip/transport/udp/udp_test.go | 3 +- test/packetimpact/testbench/BUILD | 1 + test/packetimpact/testbench/layers.go | 7 +- test/packetimpact/tests/BUILD | 3 + .../tests/ipv4_fragment_reassembly_test.go | 3 +- .../tests/ipv6_fragment_icmp_error_test.go | 3 +- .../tests/ipv6_fragment_reassembly_test.go | 3 +- 62 files changed, 611 insertions(+), 471 deletions(-) create mode 100644 pkg/tcpip/checksum/BUILD create mode 100644 pkg/tcpip/checksum/checksum.go create mode 100644 pkg/tcpip/checksum/checksum_test.go 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)