Make dedicated methods for data operations in PacketBuffer

One of the preparation to decouple underlying buffer implementation.
There are still some methods that tie to VectorisedView, and they will be
changed gradually in later CLs.

This CL also introduce a new ICMPv6ChecksumParams to replace long list of
parameters when calling ICMPv6Checksum, aiming to be more descriptive.

PiperOrigin-RevId: 360778149
This commit is contained in:
Ting-Yu Wang
2021-03-03 16:05:16 -08:00
committed by gVisor bot
parent cfd2c31962
commit 1cd76d958a
54 changed files with 959 additions and 330 deletions
+9 -1
View File
@@ -196,7 +196,7 @@ func (vv *VectorisedView) CapLength(length int) {
// If the buffer argument is large enough to contain all the Views of this
// VectorisedView, the method will avoid allocations and use the buffer to
// store the Views of the clone.
func (vv *VectorisedView) Clone(buffer []View) VectorisedView {
func (vv VectorisedView) Clone(buffer []View) VectorisedView {
return VectorisedView{views: append(buffer[:0], vv.views...), size: vv.size}
}
@@ -290,6 +290,14 @@ func (vv *VectorisedView) AppendView(v View) {
vv.size += len(v)
}
// AppendViews appends views to vv.
func (vv *VectorisedView) AppendViews(views []View) {
vv.views = append(vv.views, views...)
for _, v := range views {
vv.size += len(v)
}
}
// Readers returns a bytes.Reader for each of vv's views.
func (vv *VectorisedView) Readers() []bytes.Reader {
readers := make([]bytes.Reader, 0, len(vv.views))
+41 -5
View File
@@ -45,6 +45,11 @@ func vv(size int, pieces ...string) buffer.VectorisedView {
return buffer.NewVectorisedView(size, views)
}
// v returns a buffer.View containing piece.
func v(piece string) buffer.View {
return buffer.View(piece)
}
var capLengthTestCases = []struct {
comment string
in buffer.VectorisedView
@@ -124,6 +129,12 @@ var trimFrontTestCases = []struct {
count: 2,
want: vv(1, "3"),
},
{
comment: "Case with one empty Views",
in: vv(3, "1", "", "23"),
count: 2,
want: vv(1, "3"),
},
{
comment: "Corner case with negative count",
in: vv(1, "1"),
@@ -566,11 +577,11 @@ func TestAppendView(t *testing.T) {
in buffer.View
want buffer.VectorisedView
}{
{buffer.VectorisedView{}, nil, buffer.VectorisedView{}},
{buffer.VectorisedView{}, buffer.View{}, buffer.VectorisedView{}},
{buffer.NewVectorisedView(4, []buffer.View{{'a', 'b', 'c', 'd'}}), nil, buffer.NewVectorisedView(4, []buffer.View{{'a', 'b', 'c', 'd'}})},
{buffer.NewVectorisedView(4, []buffer.View{{'a', 'b', 'c', 'd'}}), buffer.View{}, buffer.NewVectorisedView(4, []buffer.View{{'a', 'b', 'c', 'd'}})},
{buffer.NewVectorisedView(4, []buffer.View{{'a', 'b', 'c', 'd'}}), buffer.View{'e'}, buffer.NewVectorisedView(5, []buffer.View{{'a', 'b', 'c', 'd'}, {'e'}})},
{vv(0), nil, vv(0)},
{vv(0), v(""), vv(0)},
{vv(4, "abcd"), nil, vv(4, "abcd")},
{vv(4, "abcd"), v(""), vv(4, "abcd")},
{vv(4, "abcd"), v("e"), vv(5, "abcd", "e")},
}
for _, tc := range testCases {
tc.vv.AppendView(tc.in)
@@ -580,6 +591,31 @@ func TestAppendView(t *testing.T) {
}
}
func TestAppendViews(t *testing.T) {
testCases := []struct {
vv buffer.VectorisedView
in []buffer.View
want buffer.VectorisedView
}{
{vv(0), nil, vv(0)},
{vv(0), []buffer.View{}, vv(0)},
{vv(0), []buffer.View{v("")}, vv(0, "")},
{vv(4, "abcd"), nil, vv(4, "abcd")},
{vv(4, "abcd"), []buffer.View{}, vv(4, "abcd")},
{vv(4, "abcd"), []buffer.View{v("")}, vv(4, "abcd", "")},
{vv(4, "abcd"), []buffer.View{v("")}, vv(4, "abcd", "")},
{vv(4, "abcd"), []buffer.View{v("e")}, vv(5, "abcd", "e")},
{vv(4, "abcd"), []buffer.View{v("e"), v("fg")}, vv(7, "abcd", "e", "fg")},
{vv(4, "abcd"), []buffer.View{v(""), v("fg")}, vv(6, "abcd", "", "fg")},
}
for _, tc := range testCases {
tc.vv.AppendViews(tc.in)
if got, want := tc.vv, tc.want; !reflect.DeepEqual(got, want) {
t.Errorf("(%v).ToVectorisedView failed got: %+v, want: %+v", tc.in, got, want)
}
}
}
func TestMemSize(t *testing.T) {
const perViewCap = 128
views := make([]buffer.View, 2, 32)
+5 -1
View File
@@ -985,7 +985,11 @@ func ICMPv6(checkers ...TransportChecker) NetworkChecker {
}
icmp := header.ICMPv6(last.Payload())
if got, want := icmp.Checksum(), header.ICMPv6Checksum(icmp, last.SourceAddress(), last.DestinationAddress(), buffer.VectorisedView{}); got != want {
if got, want := icmp.Checksum(), header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
Header: icmp,
Src: last.SourceAddress(),
Dst: last.DestinationAddress(),
}); got != want {
t.Fatalf("Bad ICMPv6 checksum; got %d, want %d", got, want)
}
+19 -32
View File
@@ -186,42 +186,29 @@ func Checksum(buf []byte, initial uint16) uint16 {
//
// The initial checksum must have been computed on an even number of bytes.
func ChecksumVV(vv buffer.VectorisedView, initial uint16) uint16 {
return ChecksumVVWithOffset(vv, initial, 0, vv.Size())
var c Checksumer
for _, v := range vv.Views() {
c.Add([]byte(v))
}
return ChecksumCombine(initial, c.Checksum())
}
// ChecksumVVWithOffset calculates the checksum (as defined in RFC 1071) of the
// bytes in the given VectorizedView.
//
// The initial checksum must have been computed on an even number of bytes.
func ChecksumVVWithOffset(vv buffer.VectorisedView, initial uint16, off int, size int) uint16 {
odd := false
sum := initial
for _, v := range vv.Views() {
if len(v) == 0 {
continue
}
// Checksumer calculates checksum defined in RFC 1071.
type Checksumer struct {
sum uint16
odd bool
}
if off >= len(v) {
off -= len(v)
continue
}
v = v[off:]
l := len(v)
if l > size {
l = size
}
v = v[:l]
sum, odd = unrolledCalculateChecksum(v, odd, uint32(sum))
size -= len(v)
if size == 0 {
break
}
off = 0
// 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))
}
return 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
+53 -60
View File
@@ -17,6 +17,7 @@
package header_test
import (
"bytes"
"fmt"
"math/rand"
"sync"
@@ -26,86 +27,72 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/header"
)
func TestChecksumVVWithOffset(t *testing.T) {
func TestChecksumer(t *testing.T) {
testCases := []struct {
name string
vv buffer.VectorisedView
off, size int
initial uint16
want uint16
name string
data [][]byte
want uint16
}{
{
name: "empty",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{1, 9, 0, 5, 4}),
}),
off: 0,
size: 0,
want: 0,
},
{
name: "OneView",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{1, 9, 0, 5, 4}),
}),
off: 0,
size: 5,
name: "OneOddView",
data: [][]byte{
[]byte{1, 9, 0, 5, 4},
},
want: 1294,
},
{
name: "TwoViews",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123}),
}),
off: 0,
size: 11,
name: "TwoOddViews",
data: [][]byte{
[]byte{1, 9, 0, 5, 4},
[]byte{4, 3, 7, 1, 2, 123},
},
want: 33819,
},
{
name: "TwoViewsWithOffset",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123}),
}),
off: 1,
size: 11,
want: 33819,
name: "OneEvenView",
data: [][]byte{
[]byte{1, 9, 0, 5},
},
want: 270,
},
{
name: "ThreeViewsWithOffset",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123}),
}),
off: 7,
size: 11,
want: 33819,
name: "TwoEvenViews",
data: [][]byte{
buffer.NewViewFromBytes([]byte{98, 1, 9, 0}),
buffer.NewViewFromBytes([]byte{9, 0, 5, 4}),
},
want: 30981,
},
{
name: "ThreeViewsWithInitial",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{77, 11, 33, 0, 55, 44}),
buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123, 99}),
}),
initial: 77,
off: 7,
size: 11,
want: 33896,
name: "ThreeViews",
data: [][]byte{
[]byte{77, 11, 33, 0, 55, 44},
[]byte{98, 1, 9, 0, 5, 4},
[]byte{4, 3, 7, 1, 2, 123, 99},
},
want: 34236,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if got, want := header.ChecksumVVWithOffset(tc.vv, tc.initial, tc.off, tc.size), tc.want; got != want {
t.Errorf("header.ChecksumVVWithOffset(%v) = %v, want: %v", tc, got, tc.want)
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)
}
}
v := tc.vv.ToView()
v.TrimFront(tc.off)
v.CapLength(tc.size)
if got, want := header.Checksum(v, tc.initial), tc.want; got != want {
t.Errorf("header.Checksum(%v) = %v, want: %v", tc, got, tc.want)
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)
}
})
}
@@ -228,7 +215,7 @@ func TestICMPv4Checksum(t *testing.T) {
h.SetChecksum(want)
testICMPChecksum(t, h.Checksum, func() uint16 {
return header.ICMPv4Checksum(h, vv)
return header.ICMPv4Checksum(h, header.ChecksumVV(vv, 0))
}, want, fmt.Sprintf("header: {% x} data {% x}", h, vv.ToView()))
}
@@ -260,6 +247,12 @@ func TestICMPv6Checksum(t *testing.T) {
h.SetChecksum(want)
testICMPChecksum(t, h.Checksum, func() uint16 {
return header.ICMPv6Checksum(h, src, dst, vv)
return header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
Header: h,
Src: src,
Dst: dst,
PayloadCsum: header.ChecksumVV(vv, 0),
PayloadLen: vv.Size(),
})
}, want, fmt.Sprintf("header: {% x} data {% x}", h, vv.ToView()))
}
+2 -3
View File
@@ -18,7 +18,6 @@ import (
"encoding/binary"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
)
// ICMPv4 represents an ICMPv4 header stored in a byte array.
@@ -198,8 +197,8 @@ func (b ICMPv4) SetSequence(sequence uint16) {
// ICMPv4Checksum calculates the ICMP checksum over the provided ICMP header,
// and payload.
func ICMPv4Checksum(h ICMPv4, vv buffer.VectorisedView) uint16 {
xsum := ChecksumVV(vv, 0)
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)
+13 -4
View File
@@ -18,7 +18,6 @@ import (
"encoding/binary"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
)
// ICMPv6 represents an ICMPv6 header stored in a byte array.
@@ -262,12 +261,22 @@ func (b ICMPv6) Payload() []byte {
return b[ICMPv6PayloadOffset:]
}
// ICMPv6ChecksumParams contains parameters to calculate ICMPv6 checksum.
type ICMPv6ChecksumParams struct {
Header ICMPv6
Src tcpip.Address
Dst tcpip.Address
PayloadCsum uint16
PayloadLen int
}
// ICMPv6Checksum calculates the ICMP checksum over the provided ICMPv6 header,
// IPv6 src/dst addresses and the payload.
func ICMPv6Checksum(h ICMPv6, src, dst tcpip.Address, vv buffer.VectorisedView) uint16 {
xsum := PseudoHeaderChecksum(ICMPv6ProtocolNumber, src, dst, uint16(len(h)+vv.Size()))
func ICMPv6Checksum(params ICMPv6ChecksumParams) uint16 {
h := params.Header
xsum = ChecksumVV(vv, xsum)
xsum := PseudoHeaderChecksum(ICMPv6ProtocolNumber, params.Src, params.Dst, uint16(len(h)+params.PayloadLen))
xsum = ChecksumCombine(xsum, params.PayloadCsum)
// h[2:4] is the checksum itself, skip it to avoid checksumming the checksum.
xsum = Checksum(h[:2], xsum)
+16 -14
View File
@@ -41,7 +41,7 @@ func ARP(pkt *stack.PacketBuffer) bool {
//
// Returns true if the header was successfully parsed.
func IPv4(pkt *stack.PacketBuffer) bool {
hdr, ok := pkt.Data.PullUp(header.IPv4MinimumSize)
hdr, ok := pkt.Data().PullUp(header.IPv4MinimumSize)
if !ok {
return false
}
@@ -62,27 +62,29 @@ func IPv4(pkt *stack.PacketBuffer) bool {
ipHdr = header.IPv4(hdr)
pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber
pkt.Data.CapLength(int(ipHdr.TotalLength()) - len(hdr))
pkt.Data().CapLength(int(ipHdr.TotalLength()) - len(hdr))
return true
}
// IPv6 parses an IPv6 packet found in pkt.Data and populates pkt's network
// header with the IPv6 header.
func IPv6(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, fragID uint32, fragOffset uint16, fragMore bool, ok bool) {
hdr, ok := pkt.Data.PullUp(header.IPv6MinimumSize)
hdr, ok := pkt.Data().PullUp(header.IPv6MinimumSize)
if !ok {
return 0, 0, 0, false, false
}
ipHdr := header.IPv6(hdr)
// dataClone consists of:
// Create a VV to parse the packet. We don't plan to modify anything here.
// dataVV consists of:
// - Any IPv6 header bytes after the first 40 (i.e. extensions).
// - The transport header, if present.
// - Any other payload data.
views := [8]buffer.View{}
dataClone := pkt.Data.Clone(views[:])
dataClone.TrimFront(header.IPv6MinimumSize)
it := header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(ipHdr.NextHeader()), dataClone)
dataVV := buffer.NewVectorisedView(0, views[:0])
dataVV.AppendViews(pkt.Data().Views())
dataVV.TrimFront(header.IPv6MinimumSize)
it := header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(ipHdr.NextHeader()), dataVV)
// Iterate over the IPv6 extensions to find their length.
var nextHdr tcpip.TransportProtocolNumber
@@ -98,7 +100,7 @@ traverseExtensions:
// If we exhaust the extension list, the entire packet is the IPv6 header
// and (possibly) extensions.
if done {
extensionsSize = dataClone.Size()
extensionsSize = dataVV.Size()
break
}
@@ -110,12 +112,12 @@ traverseExtensions:
fragMore = extHdr.More()
}
rawPayload := it.AsRawHeader(true /* consume */)
extensionsSize = dataClone.Size() - rawPayload.Buf.Size()
extensionsSize = dataVV.Size() - rawPayload.Buf.Size()
break traverseExtensions
case header.IPv6RawPayloadHeader:
// We've found the payload after any extensions.
extensionsSize = dataClone.Size() - extHdr.Buf.Size()
extensionsSize = dataVV.Size() - extHdr.Buf.Size()
nextHdr = tcpip.TransportProtocolNumber(extHdr.Identifier)
break traverseExtensions
@@ -127,10 +129,10 @@ traverseExtensions:
// Put the IPv6 header with extensions in pkt.NetworkHeader().
hdr, ok = pkt.NetworkHeader().Consume(header.IPv6MinimumSize + extensionsSize)
if !ok {
panic(fmt.Sprintf("pkt.Data should have at least %d bytes, but only has %d.", header.IPv6MinimumSize+extensionsSize, pkt.Data.Size()))
panic(fmt.Sprintf("pkt.Data should have at least %d bytes, but only has %d.", header.IPv6MinimumSize+extensionsSize, pkt.Data().Size()))
}
ipHdr = header.IPv6(hdr)
pkt.Data.CapLength(int(ipHdr.PayloadLength()))
pkt.Data().CapLength(int(ipHdr.PayloadLength()))
pkt.NetworkProtocolNumber = header.IPv6ProtocolNumber
return nextHdr, fragID, fragOffset, fragMore, true
@@ -153,13 +155,13 @@ func UDP(pkt *stack.PacketBuffer) bool {
func TCP(pkt *stack.PacketBuffer) bool {
// TCP header is variable length, peek at it first.
hdrLen := header.TCPMinimumSize
hdr, ok := pkt.Data.PullUp(hdrLen)
hdr, ok := pkt.Data().PullUp(hdrLen)
if !ok {
return false
}
// If the header has options, pull those up as well.
if offset := int(header.TCP(hdr).DataOffset()); offset > header.TCPMinimumSize && offset <= pkt.Data.Size() {
if offset := int(header.TCP(hdr).DataOffset()); offset > header.TCPMinimumSize && offset <= pkt.Data().Size() {
// TODO(gvisor.dev/issue/2404): Figure out whether to reject this kind of
// packets.
hdrLen = offset
+2 -2
View File
@@ -427,7 +427,7 @@ func (e *endpoint) WritePacket(r stack.RouteInfo, gso *stack.GSO, protocol tcpip
vnetHdr.csumStart = header.EthernetMinimumSize + gso.L3HdrLen
vnetHdr.csumOffset = gso.CsumOffset
}
if gso.Type != stack.GSONone && uint16(pkt.Data.Size()) > gso.MSS {
if gso.Type != stack.GSONone && uint16(pkt.Data().Size()) > gso.MSS {
switch gso.Type {
case stack.GSOTCPv4:
vnetHdr.gsoType = _VIRTIO_NET_HDR_GSO_TCPV4
@@ -468,7 +468,7 @@ func (e *endpoint) sendBatch(batchFD int, batch []*stack.PacketBuffer) (int, tcp
vnetHdr.csumStart = header.EthernetMinimumSize + pkt.GSOOptions.L3HdrLen
vnetHdr.csumOffset = pkt.GSOOptions.CsumOffset
}
if pkt.GSOOptions.Type != stack.GSONone && uint16(pkt.Data.Size()) > pkt.GSOOptions.MSS {
if pkt.GSOOptions.Type != stack.GSONone && uint16(pkt.Data().Size()) > pkt.GSOOptions.MSS {
switch pkt.GSOOptions.Type {
case stack.GSOTCPv4:
vnetHdr.gsoType = _VIRTIO_NET_HDR_GSO_TCPV4
+3 -3
View File
@@ -67,7 +67,7 @@ func checkPacketInfoEqual(t *testing.T, got, want packetInfo) {
LinkHeader: pk.LinkHeader().View(),
NetworkHeader: pk.NetworkHeader().View(),
TransportHeader: pk.TransportHeader().View(),
Data: pk.Data.ToView(),
Data: pk.Data().AsRange().ToOwnedView(),
}
}),
); diff != "" {
@@ -616,8 +616,8 @@ func TestDispatchPacketFormat(t *testing.T) {
if got, want := pkt.LinkHeader().View().Size(), header.EthernetMinimumSize; got != want {
t.Errorf("pkt.LinkHeader().View().Size() = %d, want %d", got, want)
}
if got, want := pkt.Data.Size(), 4; got != want {
t.Errorf("pkt.Data.Size() = %d, want %d", got, want)
if got, want := pkt.Data().Size(), 4; got != want {
t.Errorf("pkt.Data().Size() = %d, want %d", got, want)
}
})
}
+2 -2
View File
@@ -165,7 +165,7 @@ func (d *readVDispatcher) dispatch() (bool, tcpip.Error) {
// We don't get any indication of what the packet is, so try to guess
// if it's an IPv4 or IPv6 packet.
// IP version information is at the first octet, so pulling up 1 byte.
h, ok := pkt.Data.PullUp(1)
h, ok := pkt.Data().PullUp(1)
if !ok {
return true, nil
}
@@ -270,7 +270,7 @@ func (d *recvMMsgDispatcher) dispatch() (bool, tcpip.Error) {
// We don't get any indication of what the packet is, so try to guess
// if it's an IPv4 or IPv6 packet.
// IP version information is at the first octet, so pulling up 1 byte.
h, ok := pkt.Data.PullUp(1)
h, ok := pkt.Data().PullUp(1)
if !ok {
// Skip this packet.
continue
+3 -3
View File
@@ -80,7 +80,7 @@ func (q *queueBuffers) cleanup() {
type packetInfo struct {
addr tcpip.LinkAddress
proto tcpip.NetworkProtocolNumber
vv buffer.VectorisedView
data buffer.View
linkHeader buffer.View
}
@@ -136,7 +136,7 @@ func (c *testContext) DeliverNetworkPacket(remoteLinkAddr, localLinkAddr tcpip.L
c.packets = append(c.packets, packetInfo{
addr: remoteLinkAddr,
proto: proto,
vv: pkt.Data.Clone(nil),
data: pkt.Data().AsRange().ToOwnedView(),
})
c.mu.Unlock()
@@ -676,7 +676,7 @@ func TestSimpleReceive(t *testing.T) {
// Wait for packet to be received, then check it.
c.waitForPackets(1, time.After(5*time.Second), "Timeout waiting for packet")
c.mu.Lock()
rcvd := []byte(c.packets[0].vv.ToView())
rcvd := []byte(c.packets[0].data)
c.packets = c.packets[:0]
c.mu.Unlock()
+3 -3
View File
@@ -290,7 +290,7 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe
switch tcpip.TransportProtocolNumber(transProto) {
case header.ICMPv4ProtocolNumber:
transName = "icmp"
hdr, ok := pkt.Data.PullUp(header.ICMPv4MinimumSize)
hdr, ok := pkt.Data().PullUp(header.ICMPv4MinimumSize)
if !ok {
break
}
@@ -327,7 +327,7 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe
case header.ICMPv6ProtocolNumber:
transName = "icmp"
hdr, ok := pkt.Data.PullUp(header.ICMPv6MinimumSize)
hdr, ok := pkt.Data().PullUp(header.ICMPv6MinimumSize)
if !ok {
break
}
@@ -387,7 +387,7 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe
details += fmt.Sprintf("invalid packet: tcp data offset too small %d", offset)
break
}
if size := pkt.Data.Size() + len(tcp); offset > size && !moreFragments {
if size := pkt.Data().Size() + len(tcp); offset > size && !moreFragments {
details += fmt.Sprintf("invalid packet: tcp data offset %d larger than tcp packet length %d", offset, size)
break
}
+1 -1
View File
@@ -281,7 +281,7 @@ func (d *Device) encodePkt(info *channel.PacketInfo) (buffer.View, bool) {
vv.AppendView(info.Pkt.NetworkHeader().View())
vv.AppendView(info.Pkt.TransportHeader().View())
// Append data payload.
vv.Append(info.Pkt.Data)
vv.Append(info.Pkt.Data().ExtractVV())
return vv.ToView(), true
}
@@ -170,7 +170,7 @@ func (f *Fragmentation) Process(
return nil, 0, false, fmt.Errorf("fragment size=%d bytes is not a multiple of block size=%d on non-final fragment: %w", fragmentSize, f.blockSize, ErrInvalidArgs)
}
if l := pkt.Data.Size(); l != int(fragmentSize) {
if l := pkt.Data().Size(); l != int(fragmentSize) {
return nil, 0, false, fmt.Errorf("got fragment size=%d bytes not equal to the expected fragment size=%d bytes (first=%d last=%d): %w", l, fragmentSize, first, last, ErrInvalidArgs)
}
@@ -293,7 +293,7 @@ func MakePacketFragmenter(pkt *stack.PacketBuffer, fragmentPayloadLen uint32, re
// these headers.
var fragmentableData buffer.VectorisedView
fragmentableData.AppendView(pkt.TransportHeader().View())
fragmentableData.Append(pkt.Data)
fragmentableData.Append(pkt.Data().ExtractVV())
fragmentCount := (uint32(fragmentableData.Size()) + fragmentPayloadLen - 1) / fragmentPayloadLen
return PacketFragmenter{
@@ -323,7 +323,7 @@ func (pf *PacketFragmenter) BuildNextFragment() (*stack.PacketBuffer, int, int,
})
// Copy data for the fragment.
copied := pf.data.ReadToVV(&fragPkt.Data, pf.fragmentPayloadLen)
copied := fragPkt.Data().ReadFromVV(&pf.data, pf.fragmentPayloadLen)
offset := pf.fragmentOffset
pf.fragmentOffset += copied
@@ -121,7 +121,7 @@ func TestFragmentationProcess(t *testing.T) {
in.id, in.first, in.last, in.more, in.proto, done, c.out[i].done)
}
if c.out[i].done {
if diff := cmp.Diff(c.out[i].vv.ToOwnedView(), resPkt.Data.ToOwnedView()); diff != "" {
if diff := cmp.Diff(c.out[i].vv.ToOwnedView(), resPkt.Data().AsRange().ToOwnedView()); diff != "" {
t.Errorf("got Process(%+v, %d, %d, %t, %d, %#v) result mismatch (-want, +got):\n%s",
in.id, in.first, in.last, in.more, in.proto, in.pkt, diff)
}
@@ -470,9 +470,7 @@ func TestPacketFragmenter(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
pkt := testutil.MakeRandPkt(test.transportHeaderLen, reserve, []int{test.payloadSize}, proto)
var originalPayload buffer.VectorisedView
originalPayload.AppendView(pkt.TransportHeader().View())
originalPayload.Append(pkt.Data)
originalPayload := stack.PayloadSince(pkt.TransportHeader())
var reassembledPayload buffer.VectorisedView
pf := MakePacketFragmenter(pkt, test.fragmentPayloadLen, reserve)
for i := 0; ; i++ {
@@ -499,7 +497,7 @@ func TestPacketFragmenter(t *testing.T) {
if got := fragPkt.TransportHeader().View().Size(); got != 0 {
t.Errorf("(fragment #%d) got fragPkt.TransportHeader().View().Size() = %d, want = 0", i, got)
}
reassembledPayload.Append(fragPkt.Data)
reassembledPayload.AppendViews(fragPkt.Data().Views())
if !more {
if i != len(test.wantFragments)-1 {
t.Errorf("got fragment count = %d, want = %d", i, len(test.wantFragments)-1)
@@ -507,7 +505,7 @@ func TestPacketFragmenter(t *testing.T) {
break
}
}
if diff := cmp.Diff(reassembledPayload.ToView(), originalPayload.ToView()); diff != "" {
if diff := cmp.Diff(reassembledPayload.ToView(), originalPayload); diff != "" {
t.Errorf("reassembledPayload mismatch (-want +got):\n%s", diff)
}
})
@@ -625,11 +623,11 @@ func TestTimeoutHandler(t *testing.T) {
}
switch {
case handler.pkt != nil && test.wantPkt == nil:
t.Errorf("got handler.pkt = not nil (pkt.Data = %x), want = nil", handler.pkt.Data.ToView())
t.Errorf("got handler.pkt = not nil (pkt.Data = %x), want = nil", handler.pkt.Data().AsRange().ToOwnedView())
case handler.pkt == nil && test.wantPkt != nil:
t.Errorf("got handler.pkt = nil, want = not nil (pkt.Data = %x)", test.wantPkt.Data.ToView())
t.Errorf("got handler.pkt = nil, want = not nil (pkt.Data = %x)", test.wantPkt.Data().AsRange().ToOwnedView())
case handler.pkt != nil && test.wantPkt != nil:
if diff := cmp.Diff(test.wantPkt.Data.ToView(), handler.pkt.Data.ToView()); diff != "" {
if diff := cmp.Diff(test.wantPkt.Data().AsRange().ToOwnedView(), handler.pkt.Data().AsRange().ToOwnedView()); diff != "" {
t.Errorf("pkt.Data mismatch (-want, +got):\n%s", diff)
}
}
@@ -167,8 +167,8 @@ func (r *reassembler) process(first, last uint16, more bool, proto uint8, pkt *s
resPkt := r.holes[0].pkt
for i := 1; i < len(r.holes); i++ {
fragPkt := r.holes[i].pkt
fragPkt.Data.ReadToVV(&resPkt.Data, fragPkt.Data.Size())
fragData := r.holes[i].pkt.Data()
resPkt.Data().ReadFromData(fragData, fragData.Size())
}
return resPkt, r.proto, true, memConsumed, nil
}
@@ -204,7 +204,7 @@ func TestReassemblerProcess(t *testing.T) {
if a == nil || b == nil {
return a == b
}
return bytes.Equal(a.Data.ToOwnedView(), b.Data.ToOwnedView())
return bytes.Equal(a.Data().AsRange().ToOwnedView(), b.Data().AsRange().ToOwnedView())
}
if isDone {
+14 -7
View File
@@ -90,8 +90,7 @@ type testObject struct {
// checkValues verifies that the transport protocol, data contents, src & dst
// addresses of a packet match what's expected. If any field doesn't match, the
// test fails.
func (t *testObject) checkValues(protocol tcpip.TransportProtocolNumber, vv buffer.VectorisedView, srcAddr, dstAddr tcpip.Address) {
v := vv.ToView()
func (t *testObject) checkValues(protocol tcpip.TransportProtocolNumber, v buffer.View, srcAddr, dstAddr tcpip.Address) {
if protocol != t.protocol {
t.t.Errorf("protocol = %v, want %v", protocol, t.protocol)
}
@@ -120,7 +119,7 @@ func (t *testObject) checkValues(protocol tcpip.TransportProtocolNumber, vv buff
// parsing are expected.
func (t *testObject) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt *stack.PacketBuffer) stack.TransportPacketDisposition {
netHdr := pkt.Network()
t.checkValues(protocol, pkt.Data, netHdr.SourceAddress(), netHdr.DestinationAddress())
t.checkValues(protocol, pkt.Data().AsRange().ToOwnedView(), netHdr.SourceAddress(), netHdr.DestinationAddress())
t.dataCalls++
return stack.TransportPacketHandled
}
@@ -129,7 +128,7 @@ func (t *testObject) DeliverTransportPacket(protocol tcpip.TransportProtocolNumb
// incoming control (ICMP) packets. This is used by the test object to verify
// that the results of the parsing are expected.
func (t *testObject) DeliverTransportError(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr stack.TransportError, pkt *stack.PacketBuffer) {
t.checkValues(trans, pkt.Data, remote, local)
t.checkValues(trans, pkt.Data().AsRange().ToOwnedView(), remote, local)
if diff := cmp.Diff(
t.transErr,
transportError{
@@ -198,7 +197,7 @@ func (t *testObject) WritePacket(_ *stack.Route, _ *stack.GSO, protocol tcpip.Ne
srcAddr = h.SourceAddress()
dstAddr = h.DestinationAddress()
}
t.checkValues(prot, pkt.Data, srcAddr, dstAddr)
t.checkValues(prot, pkt.Data().AsRange().ToOwnedView(), srcAddr, dstAddr)
return nil
}
@@ -371,7 +370,11 @@ func TestSourceAddressValidation(t *testing.T) {
pkt.SetType(header.ICMPv6EchoRequest)
pkt.SetCode(0)
pkt.SetChecksum(0)
pkt.SetChecksum(header.ICMPv6Checksum(pkt, src, localIPv6Addr, buffer.VectorisedView{}))
pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
Header: pkt,
Src: src,
Dst: localIPv6Addr,
}))
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: header.ICMPv6MinimumSize,
@@ -1199,7 +1202,11 @@ func TestIPv6ReceiveControl(t *testing.T) {
nic.testObject.transErr = c.transErr
// Set ICMPv6 checksum.
icmp.SetChecksum(header.ICMPv6Checksum(icmp, outerSrcAddr, localIPv6Addr, buffer.VectorisedView{}))
icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
Header: icmp,
Src: outerSrcAddr,
Dst: localIPv6Addr,
}))
addressableEndpoint, ok := ep.(stack.AddressableEndpoint)
if !ok {
+14 -11
View File
@@ -137,7 +137,7 @@ func (e *endpoint) checkLocalAddress(addr tcpip.Address) bool {
// is used to find out which transport endpoint must be notified about the ICMP
// packet. We only expect the payload, not the enclosing ICMP packet.
func (e *endpoint) handleControl(errInfo stack.TransportError, pkt *stack.PacketBuffer) {
h, ok := pkt.Data.PullUp(header.IPv4MinimumSize)
h, ok := pkt.Data().PullUp(header.IPv4MinimumSize)
if !ok {
return
}
@@ -156,7 +156,7 @@ func (e *endpoint) handleControl(errInfo stack.TransportError, pkt *stack.Packet
}
hlen := int(hdr.HeaderLength())
if pkt.Data.Size() < hlen || hdr.FragmentOffset() != 0 {
if pkt.Data().Size() < hlen || hdr.FragmentOffset() != 0 {
// We won't be able to handle this if it doesn't contain the
// full IPv4 header, or if it's a fragment not at offset 0
// (because it won't have the transport header).
@@ -164,7 +164,7 @@ func (e *endpoint) handleControl(errInfo stack.TransportError, pkt *stack.Packet
}
// Skip the ip header, then deliver the error.
pkt.Data.TrimFront(hlen)
pkt.Data().TrimFront(hlen)
p := hdr.TransportProtocol()
e.dispatcher.DeliverTransportError(srcAddr, hdr.DestinationAddress(), ProtocolNumber, p, errInfo, pkt)
}
@@ -174,7 +174,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
// TODO(gvisor.dev/issue/170): ICMP packets don't have their
// TransportHeader fields set. See icmp/protocol.go:protocol.Parse for a
// full explanation.
v, ok := pkt.Data.PullUp(header.ICMPv4MinimumSize)
v, ok := pkt.Data().PullUp(header.ICMPv4MinimumSize)
if !ok {
received.invalid.Increment()
return
@@ -182,7 +182,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
h := header.ICMPv4(v)
// Only do in-stack processing if the checksum is correct.
if header.ChecksumVV(pkt.Data, 0 /* initial */) != 0xffff {
if pkt.Data().AsRange().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
@@ -253,7 +253,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
// TODO(gvisor.dev/issue/4399): The copy may not be needed if there are no
// waiting endpoints. Consider moving responsibility for doing the copy to
// DeliverTransportPacket so that is is only done when needed.
replyData := pkt.Data.ToOwnedView()
replyData := pkt.Data().AsRange().ToOwnedView()
ipHdr := header.IPv4(pkt.NetworkHeader().View())
localAddressBroadcast := pkt.NetworkPacketInfo.LocalAddressBroadcast
@@ -336,7 +336,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
case header.ICMPv4DstUnreachable:
received.dstUnreachable.Increment()
pkt.Data.TrimFront(header.ICMPv4MinimumSize)
pkt.Data().TrimFront(header.ICMPv4MinimumSize)
switch h.Code() {
case header.ICMPv4HostUnreachable:
e.handleControl(&icmpv4DestinationHostUnreachableSockError{}, pkt)
@@ -571,7 +571,7 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) tcpip
return nil
}
payloadLen := len(origIPHdr) + transportHeader.Size() + pkt.Data.Size()
payloadLen := len(origIPHdr) + transportHeader.Size() + pkt.Data().Size()
if payloadLen > available {
payloadLen = available
}
@@ -586,8 +586,11 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) tcpip
newHeader := append(buffer.View(nil), origIPHdr...)
newHeader = append(newHeader, transportHeader...)
payload := newHeader.ToVectorisedView()
payload.AppendView(pkt.Data.ToView())
payload.CapLength(payloadLen)
if dataCap := payloadLen - payload.Size(); dataCap > 0 {
payload.AppendView(pkt.Data().AsRange().Capped(dataCap).ToOwnedView())
} else {
payload.CapLength(payloadLen)
}
icmpPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: int(route.MaxHeaderLength()) + header.ICMPv4MinimumSize,
@@ -623,7 +626,7 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) tcpip
default:
panic(fmt.Sprintf("unsupported ICMP type %T", reason))
}
icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data))
icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data().AsRange().Checksum()))
if err := route.WritePacket(
nil, /* gso */

Some files were not shown because too many files have changed in this diff Show More