Always pass buffer.VectorisedView by value

PiperOrigin-RevId: 212757571
Change-Id: I04200df9e45c21eb64951cd2802532fa84afcb1a
This commit is contained in:
Tamir Duberstein
2018-09-12 21:57:55 -07:00
committed by Shentubot
parent 5adb3468d4
commit d689f8422f
44 changed files with 361 additions and 436 deletions
+1 -5
View File
@@ -42,11 +42,7 @@ func createStack(t *testing.T) *stack.Stack {
go func() {
for pkt := range linkEP.C {
v := make(buffer.View, len(pkt.Header)+len(pkt.Payload))
copy(v, pkt.Header)
copy(v[len(pkt.Header):], pkt.Payload)
vv := v.ToVectorisedView([1]buffer.View{})
linkEP.Inject(pkt.Proto, &vv)
linkEP.Inject(pkt.Proto, buffer.NewVectorisedView(len(pkt.Header)+len(pkt.Payload), []buffer.View{pkt.Header, pkt.Payload}))
}
}()
+1 -2
View File
@@ -350,8 +350,7 @@ func (c *Conn) Write(b []byte) (int, error) {
default:
}
v := buffer.NewView(len(b))
copy(v, b)
v := buffer.NewViewFromBytes(b)
// We must handle two soft failure conditions simultaneously:
// 1. Write may write nothing and return tcpip.ErrWouldBlock.
+9 -53
View File
@@ -45,11 +45,9 @@ func (v *View) CapLength(length int) {
*v = (*v)[:length:length]
}
// ToVectorisedView transforms a View in a VectorisedView from an
// already-allocated slice of View.
func (v *View) ToVectorisedView(views [1]View) VectorisedView {
views[0] = *v
return NewVectorisedView(len(*v), views[:])
// ToVectorisedView returns a VectorisedView containing the receiver.
func (v View) ToVectorisedView() VectorisedView {
return NewVectorisedView(len(v), []View{v})
}
// VectorisedView is a vectorised version of View using non contigous memory.
@@ -107,21 +105,12 @@ func (vv *VectorisedView) CapLength(length int) {
// Clone returns a clone of this VectorisedView.
// 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 {
var views []View
if len(buffer) >= len(vv.views) {
views = buffer[:len(vv.views)]
} else {
views = make([]View, len(vv.views))
}
for i, v := range vv.views {
views[i] = v
}
return VectorisedView{views: views, size: vv.size}
func (vv VectorisedView) Clone(buffer []View) VectorisedView {
return VectorisedView{views: append(buffer[:0], vv.views...), size: vv.size}
}
// First returns the first view of the vectorised view.
func (vv *VectorisedView) First() View {
func (vv VectorisedView) First() View {
if len(vv.views) == 0 {
return nil
}
@@ -137,23 +126,13 @@ func (vv *VectorisedView) RemoveFirst() {
vv.views = vv.views[1:]
}
// SetSize unsafely sets the size of the VectorisedView.
func (vv *VectorisedView) SetSize(size int) {
vv.size = size
}
// SetViews unsafely sets the views of the VectorisedView.
func (vv *VectorisedView) SetViews(views []View) {
vv.views = views
}
// Size returns the size in bytes of the entire content stored in the vectorised view.
func (vv *VectorisedView) Size() int {
func (vv VectorisedView) Size() int {
return vv.size
}
// ToView returns a single view containing the content of the vectorised view.
func (vv *VectorisedView) ToView() View {
func (vv VectorisedView) ToView() View {
u := make([]byte, 0, vv.size)
for _, v := range vv.views {
u = append(u, v...)
@@ -162,29 +141,6 @@ func (vv *VectorisedView) ToView() View {
}
// Views returns the slice containing the all views.
func (vv *VectorisedView) Views() []View {
func (vv VectorisedView) Views() []View {
return vv.views
}
// ByteSlice returns a slice containing the all views as a []byte.
func (vv *VectorisedView) ByteSlice() [][]byte {
s := make([][]byte, len(vv.views))
for i := range vv.views {
s[i] = []byte(vv.views[i])
}
return s
}
// copy returns a deep-copy of the vectorised view.
// It is an expensive method that should be used only in tests.
func (vv *VectorisedView) copy() *VectorisedView {
uu := &VectorisedView{
views: make([]View, len(vv.views)),
size: vv.size,
}
for i, v := range vv.views {
uu.views[i] = make(View, len(v))
copy(uu.views[i], v)
}
return uu
}
+27 -14
View File
@@ -20,22 +20,33 @@ import (
"testing"
)
// copy returns a deep-copy of the vectorised view.
func (vv VectorisedView) copy() VectorisedView {
uu := VectorisedView{
views: make([]View, 0, len(vv.views)),
size: vv.size,
}
for _, v := range vv.views {
uu.views = append(uu.views, append(View(nil), v...))
}
return uu
}
// vv is an helper to build VectorisedView from different strings.
func vv(size int, pieces ...string) *VectorisedView {
func vv(size int, pieces ...string) VectorisedView {
views := make([]View, len(pieces))
for i, p := range pieces {
views[i] = []byte(p)
}
vv := NewVectorisedView(size, views)
return &vv
return NewVectorisedView(size, views)
}
var capLengthTestCases = []struct {
comment string
in *VectorisedView
in VectorisedView
length int
want *VectorisedView
want VectorisedView
}{
{
comment: "Simple case",
@@ -88,9 +99,9 @@ func TestCapLength(t *testing.T) {
var trimFrontTestCases = []struct {
comment string
in *VectorisedView
in VectorisedView
count int
want *VectorisedView
want VectorisedView
}{
{
comment: "Simple case",
@@ -149,7 +160,7 @@ func TestTrimFront(t *testing.T) {
var toViewCases = []struct {
comment string
in *VectorisedView
in VectorisedView
want View
}{
{
@@ -181,7 +192,7 @@ func TestToView(t *testing.T) {
var toCloneCases = []struct {
comment string
inView *VectorisedView
inView VectorisedView
inBuffer []View
}{
{
@@ -213,10 +224,12 @@ var toCloneCases = []struct {
func TestToClone(t *testing.T) {
for _, c := range toCloneCases {
got := c.inView.Clone(c.inBuffer)
if !reflect.DeepEqual(&got, c.inView) {
t.Errorf("Test \"%s\" failed when calling Clone(%v) on %v. Got %v. Want %v",
c.comment, c.inBuffer, c.inView, got, c.inView)
}
t.Run(c.comment, func(t *testing.T) {
got := c.inView.Clone(c.inBuffer)
if !reflect.DeepEqual(got, c.inView) {
t.Fatalf("got (%+v).Clone(%+v) = %+v, want = %+v",
c.inView, c.inBuffer, got, c.inView)
}
})
}
}
+89 -44
View File
@@ -39,40 +39,52 @@ type TransportChecker func(*testing.T, header.Transport)
//
// checker.IPv4(t, b, checker.SrcAddr(x), checker.DstAddr(y))
func IPv4(t *testing.T, b []byte, checkers ...NetworkChecker) {
t.Helper()
ipv4 := header.IPv4(b)
if !ipv4.IsValid(len(b)) {
t.Fatalf("Not a valid IPv4 packet")
t.Error("Not a valid IPv4 packet")
}
xsum := ipv4.CalculateChecksum()
if xsum != 0 && xsum != 0xffff {
t.Fatalf("Bad checksum: 0x%x, checksum in packet: 0x%x", xsum, ipv4.Checksum())
t.Errorf("Bad checksum: 0x%x, checksum in packet: 0x%x", xsum, ipv4.Checksum())
}
for _, f := range checkers {
f(t, []header.Network{ipv4})
}
if t.Failed() {
t.FailNow()
}
}
// IPv6 checks the validity and properties of the given IPv6 packet. The usage
// is similar to IPv4.
func IPv6(t *testing.T, b []byte, checkers ...NetworkChecker) {
t.Helper()
ipv6 := header.IPv6(b)
if !ipv6.IsValid(len(b)) {
t.Fatalf("Not a valid IPv6 packet")
t.Error("Not a valid IPv6 packet")
}
for _, f := range checkers {
f(t, []header.Network{ipv6})
}
if t.Failed() {
t.FailNow()
}
}
// SrcAddr creates a checker that checks the source address.
func SrcAddr(addr tcpip.Address) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
if a := h[0].SourceAddress(); a != addr {
t.Fatalf("Bad source address, got %v, want %v", a, addr)
t.Errorf("Bad source address, got %v, want %v", a, addr)
}
}
}
@@ -80,8 +92,10 @@ func SrcAddr(addr tcpip.Address) NetworkChecker {
// DstAddr creates a checker that checks the destination address.
func DstAddr(addr tcpip.Address) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
if a := h[0].DestinationAddress(); a != addr {
t.Fatalf("Bad destination address, got %v, want %v", a, addr)
t.Errorf("Bad destination address, got %v, want %v", a, addr)
}
}
}
@@ -105,8 +119,10 @@ func TTL(ttl uint8) NetworkChecker {
// PayloadLen creates a checker that checks the payload length.
func PayloadLen(plen int) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
if l := len(h[0].Payload()); l != plen {
t.Fatalf("Bad payload length, got %v, want %v", l, plen)
t.Errorf("Bad payload length, got %v, want %v", l, plen)
}
}
}
@@ -114,11 +130,13 @@ func PayloadLen(plen int) NetworkChecker {
// FragmentOffset creates a checker that checks the FragmentOffset field.
func FragmentOffset(offset uint16) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
// We only do this of IPv4 for now.
switch ip := h[0].(type) {
case header.IPv4:
if v := ip.FragmentOffset(); v != offset {
t.Fatalf("Bad fragment offset, got %v, want %v", v, offset)
t.Errorf("Bad fragment offset, got %v, want %v", v, offset)
}
}
}
@@ -127,11 +145,13 @@ func FragmentOffset(offset uint16) NetworkChecker {
// FragmentFlags creates a checker that checks the fragment flags field.
func FragmentFlags(flags uint8) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
// We only do this of IPv4 for now.
switch ip := h[0].(type) {
case header.IPv4:
if v := ip.Flags(); v != flags {
t.Fatalf("Bad fragment offset, got %v, want %v", v, flags)
t.Errorf("Bad fragment offset, got %v, want %v", v, flags)
}
}
}
@@ -140,8 +160,10 @@ func FragmentFlags(flags uint8) NetworkChecker {
// TOS creates a checker that checks the TOS field.
func TOS(tos uint8, label uint32) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
if v, l := h[0].TOS(); v != tos || l != label {
t.Fatalf("Bad TOS, got (%v, %v), want (%v,%v)", v, l, tos, label)
t.Errorf("Bad TOS, got (%v, %v), want (%v,%v)", v, l, tos, label)
}
}
}
@@ -153,8 +175,10 @@ func TOS(tos uint8, label uint32) NetworkChecker {
// the bytes added by the IPv6 fragmentation.
func Raw(want []byte) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
if got := h[len(h)-1].Payload(); !reflect.DeepEqual(got, want) {
t.Fatalf("Wrong payload, got %v, want %v", got, want)
t.Errorf("Wrong payload, got %v, want %v", got, want)
}
}
}
@@ -162,18 +186,23 @@ func Raw(want []byte) NetworkChecker {
// IPv6Fragment creates a checker that validates an IPv6 fragment.
func IPv6Fragment(checkers ...NetworkChecker) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
if p := h[0].TransportProtocol(); p != header.IPv6FragmentHeader {
t.Fatalf("Bad protocol, got %v, want %v", p, header.UDPProtocolNumber)
t.Errorf("Bad protocol, got %v, want %v", p, header.UDPProtocolNumber)
}
ipv6Frag := header.IPv6Fragment(h[0].Payload())
if !ipv6Frag.IsValid() {
t.Fatalf("Not a valid IPv6 fragment")
t.Error("Not a valid IPv6 fragment")
}
for _, f := range checkers {
f(t, []header.Network{h[0], ipv6Frag})
}
if t.Failed() {
t.FailNow()
}
}
}
@@ -181,11 +210,13 @@ func IPv6Fragment(checkers ...NetworkChecker) NetworkChecker {
// potentially additional transport header fields.
func TCP(checkers ...TransportChecker) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
first := h[0]
last := h[len(h)-1]
if p := last.TransportProtocol(); p != header.TCPProtocolNumber {
t.Fatalf("Bad protocol, got %v, want %v", p, header.TCPProtocolNumber)
t.Errorf("Bad protocol, got %v, want %v", p, header.TCPProtocolNumber)
}
// Verify the checksum.
@@ -199,13 +230,16 @@ func TCP(checkers ...TransportChecker) NetworkChecker {
xsum = header.Checksum(tcp, xsum)
if xsum != 0 && xsum != 0xffff {
t.Fatalf("Bad checksum: 0x%x, checksum in segment: 0x%x", xsum, tcp.Checksum())
t.Errorf("Bad checksum: 0x%x, checksum in segment: 0x%x", xsum, tcp.Checksum())
}
// Run the transport checkers.
for _, f := range checkers {
f(t, tcp)
}
if t.Failed() {
t.FailNow()
}
}
}
@@ -213,24 +247,31 @@ func TCP(checkers ...TransportChecker) NetworkChecker {
// potentially additional transport header fields.
func UDP(checkers ...TransportChecker) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
last := h[len(h)-1]
if p := last.TransportProtocol(); p != header.UDPProtocolNumber {
t.Fatalf("Bad protocol, got %v, want %v", p, header.UDPProtocolNumber)
t.Errorf("Bad protocol, got %v, want %v", p, header.UDPProtocolNumber)
}
udp := header.UDP(last.Payload())
for _, f := range checkers {
f(t, udp)
}
if t.Failed() {
t.FailNow()
}
}
}
// SrcPort creates a checker that checks the source port.
func SrcPort(port uint16) TransportChecker {
return func(t *testing.T, h header.Transport) {
t.Helper()
if p := h.SourcePort(); p != port {
t.Fatalf("Bad source port, got %v, want %v", p, port)
t.Errorf("Bad source port, got %v, want %v", p, port)
}
}
}
@@ -239,7 +280,7 @@ func SrcPort(port uint16) TransportChecker {
func DstPort(port uint16) TransportChecker {
return func(t *testing.T, h header.Transport) {
if p := h.DestinationPort(); p != port {
t.Fatalf("Bad destination port, got %v, want %v", p, port)
t.Errorf("Bad destination port, got %v, want %v", p, port)
}
}
}
@@ -247,13 +288,15 @@ func DstPort(port uint16) TransportChecker {
// SeqNum creates a checker that checks the sequence number.
func SeqNum(seq uint32) TransportChecker {
return func(t *testing.T, h header.Transport) {
t.Helper()
tcp, ok := h.(header.TCP)
if !ok {
return
}
if s := tcp.SequenceNumber(); s != seq {
t.Fatalf("Bad sequence number, got %v, want %v", s, seq)
t.Errorf("Bad sequence number, got %v, want %v", s, seq)
}
}
}
@@ -268,7 +311,7 @@ func AckNum(seq uint32) TransportChecker {
}
if s := tcp.AckNumber(); s != seq {
t.Fatalf("Bad ack number, got %v, want %v", s, seq)
t.Errorf("Bad ack number, got %v, want %v", s, seq)
}
}
}
@@ -282,7 +325,7 @@ func Window(window uint16) TransportChecker {
}
if w := tcp.WindowSize(); w != window {
t.Fatalf("Bad window, got 0x%x, want 0x%x", w, window)
t.Errorf("Bad window, got 0x%x, want 0x%x", w, window)
}
}
}
@@ -290,13 +333,15 @@ func Window(window uint16) TransportChecker {
// TCPFlags creates a checker that checks the tcp flags.
func TCPFlags(flags uint8) TransportChecker {
return func(t *testing.T, h header.Transport) {
t.Helper()
tcp, ok := h.(header.TCP)
if !ok {
return
}
if f := tcp.Flags(); f != flags {
t.Fatalf("Bad flags, got 0x%x, want 0x%x", f, flags)
t.Errorf("Bad flags, got 0x%x, want 0x%x", f, flags)
}
}
}
@@ -311,7 +356,7 @@ func TCPFlagsMatch(flags, mask uint8) TransportChecker {
}
if f := tcp.Flags(); (f & mask) != (flags & mask) {
t.Fatalf("Bad masked flags, got 0x%x, want 0x%x, mask 0x%x", f, flags, mask)
t.Errorf("Bad masked flags, got 0x%x, want 0x%x, mask 0x%x", f, flags, mask)
}
}
}
@@ -343,26 +388,26 @@ func TCPSynOptions(wantOpts header.TCPSynOptions) TransportChecker {
case header.TCPOptionMSS:
v := uint16(opts[i+2])<<8 | uint16(opts[i+3])
if wantOpts.MSS != v {
t.Fatalf("Bad MSS: got %v, want %v", v, wantOpts.MSS)
t.Errorf("Bad MSS: got %v, want %v", v, wantOpts.MSS)
}
foundMSS = true
i += 4
case header.TCPOptionWS:
if wantOpts.WS < 0 {
t.Fatalf("WS present when it shouldn't be")
t.Error("WS present when it shouldn't be")
}
v := int(opts[i+2])
if v != wantOpts.WS {
t.Fatalf("Bad WS: got %v, want %v", v, wantOpts.WS)
t.Errorf("Bad WS: got %v, want %v", v, wantOpts.WS)
}
foundWS = true
i += 3
case header.TCPOptionTS:
if i+9 >= limit {
t.Fatalf("TS Option truncated , option is only: %d bytes, want 10", limit-i)
t.Errorf("TS Option truncated , option is only: %d bytes, want 10", limit-i)
}
if opts[i+1] != 10 {
t.Fatalf("Bad length %d for TS option, limit: %d", opts[i+1], limit)
t.Errorf("Bad length %d for TS option, limit: %d", opts[i+1], limit)
}
tsVal = binary.BigEndian.Uint32(opts[i+2:])
tsEcr = uint32(0)
@@ -375,10 +420,10 @@ func TCPSynOptions(wantOpts header.TCPSynOptions) TransportChecker {
i += 10
case header.TCPOptionSACKPermitted:
if i+1 >= limit {
t.Fatalf("SACKPermitted option truncated, option is only : %d bytes, want 2", limit-i)
t.Errorf("SACKPermitted option truncated, option is only : %d bytes, want 2", limit-i)
}
if opts[i+1] != 2 {
t.Fatalf("Bad length %d for SACKPermitted option, limit: %d", opts[i+1], limit)
t.Errorf("Bad length %d for SACKPermitted option, limit: %d", opts[i+1], limit)
}
foundSACKPermitted = true
i += 2
@@ -389,23 +434,23 @@ func TCPSynOptions(wantOpts header.TCPSynOptions) TransportChecker {
}
if !foundMSS {
t.Fatalf("MSS option not found. Options: %x", opts)
t.Errorf("MSS option not found. Options: %x", opts)
}
if !foundWS && wantOpts.WS >= 0 {
t.Fatalf("WS option not found. Options: %x", opts)
t.Errorf("WS option not found. Options: %x", opts)
}
if wantOpts.TS && !foundTS {
t.Fatalf("TS option not found. Options: %x", opts)
t.Errorf("TS option not found. Options: %x", opts)
}
if foundTS && tsVal == 0 {
t.Fatalf("TS option specified but the timestamp value is zero")
t.Error("TS option specified but the timestamp value is zero")
}
if foundTS && tsEcr == 0 && wantOpts.TSEcr != 0 {
t.Fatalf("TS option specified but TSEcr is incorrect: got %d, want: %d", tsEcr, wantOpts.TSEcr)
t.Errorf("TS option specified but TSEcr is incorrect: got %d, want: %d", tsEcr, wantOpts.TSEcr)
}
if wantOpts.SACKPermitted && !foundSACKPermitted {
t.Fatalf("SACKPermitted option not found. Options: %x", opts)
t.Errorf("SACKPermitted option not found. Options: %x", opts)
}
}
}
@@ -435,10 +480,10 @@ func TCPTimestampChecker(wantTS bool, wantTSVal uint32, wantTSEcr uint32) Transp
i++
case header.TCPOptionTS:
if i+9 >= limit {
t.Fatalf("TS option found, but option is truncated, option length: %d, want 10 bytes", limit-i)
t.Errorf("TS option found, but option is truncated, option length: %d, want 10 bytes", limit-i)
}
if opts[i+1] != 10 {
t.Fatalf("TS option found, but bad length specified: %d, want: 10", opts[i+1])
t.Errorf("TS option found, but bad length specified: %d, want: 10", opts[i+1])
}
tsVal = binary.BigEndian.Uint32(opts[i+2:])
tsEcr = binary.BigEndian.Uint32(opts[i+6:])
@@ -458,13 +503,13 @@ func TCPTimestampChecker(wantTS bool, wantTSVal uint32, wantTSEcr uint32) Transp
}
if wantTS != foundTS {
t.Fatalf("TS Option mismatch: got TS= %v, want TS= %v", foundTS, wantTS)
t.Errorf("TS Option mismatch: got TS= %v, want TS= %v", foundTS, wantTS)
}
if wantTS && wantTSVal != 0 && wantTSVal != tsVal {
t.Fatalf("Timestamp value is incorrect: got: %d, want: %d", tsVal, wantTSVal)
t.Errorf("Timestamp value is incorrect: got: %d, want: %d", tsVal, wantTSVal)
}
if wantTS && wantTSEcr != 0 && tsEcr != wantTSEcr {
t.Fatalf("Timestamp Echo Reply is incorrect: got: %d, want: %d", tsEcr, wantTSEcr)
t.Errorf("Timestamp Echo Reply is incorrect: got: %d, want: %d", tsEcr, wantTSEcr)
}
}
}
@@ -497,12 +542,12 @@ func TCPSACKBlockChecker(sackBlocks []header.SACKBlock) TransportChecker {
case header.TCPOptionSACK:
if i+2 > limit {
// Malformed SACK block.
t.Fatalf("malformed SACK option in options: %v", opts)
t.Errorf("malformed SACK option in options: %v", opts)
}
sackOptionLen := int(opts[i+1])
if i+sackOptionLen > limit || (sackOptionLen-2)%8 != 0 {
// Malformed SACK block.
t.Fatalf("malformed SACK option length in options: %v", opts)
t.Errorf("malformed SACK option length in options: %v", opts)
}
numBlocks := sackOptionLen / 8
for j := 0; j < numBlocks; j++ {
@@ -528,7 +573,7 @@ func TCPSACKBlockChecker(sackBlocks []header.SACKBlock) TransportChecker {
}
if !reflect.DeepEqual(gotSACKBlocks, sackBlocks) {
t.Fatalf("SACKBlocks are not equal, got: %v, want: %v", gotSACKBlocks, sackBlocks)
t.Errorf("SACKBlocks are not equal, got: %v, want: %v", gotSACKBlocks, sackBlocks)
}
}
}
@@ -537,7 +582,7 @@ func TCPSACKBlockChecker(sackBlocks []header.SACKBlock) TransportChecker {
func Payload(want []byte) TransportChecker {
return func(t *testing.T, h header.Transport) {
if got := h.Payload(); !reflect.DeepEqual(got, want) {
t.Fatalf("Wrong payload, got %v, want %v", got, want)
t.Errorf("Wrong payload, got %v, want %v", got, want)
}
}
}
+4 -6
View File
@@ -66,15 +66,13 @@ func (e *Endpoint) Drain() int {
}
// Inject injects an inbound packet.
func (e *Endpoint) Inject(protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
uu := vv.Clone(nil)
e.dispatcher.DeliverNetworkPacket(e, "", protocol, &uu)
func (e *Endpoint) Inject(protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
e.InjectLinkAddr(protocol, "", vv)
}
// InjectLinkAddr injects an inbound packet with a remote link address.
func (e *Endpoint) InjectLinkAddr(protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, vv *buffer.VectorisedView) {
uu := vv.Clone(nil)
e.dispatcher.DeliverNetworkPacket(e, remoteLinkAddr, protocol, &uu)
func (e *Endpoint) InjectLinkAddr(protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, vv buffer.VectorisedView) {
e.dispatcher.DeliverNetworkPacket(e, remoteLinkAddr, protocol, vv.Clone(nil))
}
// Attach saves the stack network-layer dispatcher for use later when packets
+5 -9
View File
@@ -57,7 +57,6 @@ type endpoint struct {
// its end of the communication pipe.
closed func(*tcpip.Error)
vv *buffer.VectorisedView
iovecs []syscall.Iovec
views []buffer.View
dispatcher stack.NetworkDispatcher
@@ -118,8 +117,6 @@ func New(opts *Options) tcpip.LinkEndpointID {
iovecs: make([]syscall.Iovec, len(BufConfig)),
handleLocal: opts.HandleLocal,
}
vv := buffer.NewVectorisedView(0, e.views)
e.vv = &vv
return stack.RegisterLinkEndpoint(e)
}
@@ -167,7 +164,7 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload
views[0] = hdr.View()
views = append(views, payload.Views()...)
vv := buffer.NewVectorisedView(len(views[0])+payload.Size(), views)
e.dispatcher.DeliverNetworkPacket(e, r.RemoteLinkAddress, protocol, &vv)
e.dispatcher.DeliverNetworkPacket(e, r.RemoteLinkAddress, protocol, vv)
return nil
}
if e.hdrSize > 0 {
@@ -246,11 +243,10 @@ func (e *endpoint) dispatch(largeV buffer.View) (bool, *tcpip.Error) {
}
used := e.capViews(n, BufConfig)
e.vv.SetViews(e.views[:used])
e.vv.SetSize(n)
e.vv.TrimFront(e.hdrSize)
vv := buffer.NewVectorisedView(n, e.views[:used])
vv.TrimFront(e.hdrSize)
e.dispatcher.DeliverNetworkPacket(e, addr, p, e.vv)
e.dispatcher.DeliverNetworkPacket(e, addr, p, vv)
// Prepare e.views for another packet: release used views.
for i := 0; i < used; i++ {
@@ -290,7 +286,7 @@ func (e *InjectableEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
}
// Inject injects an inbound packet.
func (e *InjectableEndpoint) Inject(protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
func (e *InjectableEndpoint) Inject(protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
e.dispatcher.DeliverNetworkPacket(e, "", protocol, vv)
}
+2 -3
View File
@@ -77,7 +77,7 @@ func (c *context) cleanup() {
syscall.Close(c.fds[1])
}
func (c *context) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
func (c *context) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
c.ch <- packetInfo{remoteLinkAddr, protocol, vv.ToView()}
}
@@ -158,8 +158,7 @@ func TestWritePacket(t *testing.T) {
payload[i] = uint8(rand.Intn(256))
}
want := append(hdr.UsedBytes(), payload...)
vv := buffer.NewVectorisedView(len(payload), []buffer.View{payload})
if err := c.ep.WritePacket(r, &hdr, vv, proto); err != nil {
if err := c.ep.WritePacket(r, &hdr, payload.ToVectorisedView(), proto); err != nil {
t.Fatalf("WritePacket failed: %v", err)
}
+1 -1
View File
@@ -77,7 +77,7 @@ func (e *endpoint) WritePacket(_ *stack.Route, hdr *buffer.Prependable, payload
views[0] = hdr.View()
views = append(views, payload.Views()...)
vv := buffer.NewVectorisedView(len(views[0])+payload.Size(), views)
e.dispatcher.DeliverNetworkPacket(e, "", protocol, &vv)
e.dispatcher.DeliverNetworkPacket(e, "", protocol, vv)
return nil
}
+1 -5
View File
@@ -227,8 +227,6 @@ func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) {
// Read in a loop until a stop is requested.
var rxb []queue.RxBuffer
views := []buffer.View{nil}
vv := buffer.NewVectorisedView(0, views)
for atomic.LoadUint32(&e.stopRequested) == 0 {
var n uint32
rxb, n = e.rx.postAndReceive(rxb, &e.stopRequested)
@@ -250,9 +248,7 @@ func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) {
// Send packet up the stack.
eth := header.Ethernet(b)
views[0] = b[header.EthernetMinimumSize:]
vv.SetSize(int(n) - header.EthernetMinimumSize)
d.DeliverNetworkPacket(e, eth.SourceAddress(), eth.Type(), &vv)
d.DeliverNetworkPacket(e, eth.SourceAddress(), eth.Type(), buffer.View(b[header.EthernetMinimumSize:]).ToVectorisedView())
}
// Clean state.
+24 -23
View File
@@ -129,7 +129,7 @@ func newTestContext(t *testing.T, mtu, bufferSize uint32, addr tcpip.LinkAddress
return c
}
func (c *testContext) DeliverNetworkPacket(_ stack.LinkEndpoint, remoteAddr tcpip.LinkAddress, proto tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
func (c *testContext) DeliverNetworkPacket(_ stack.LinkEndpoint, remoteAddr tcpip.LinkAddress, proto tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
c.mu.Lock()
c.packets = append(c.packets, packetInfo{
addr: remoteAddr,
@@ -270,8 +270,7 @@ func TestSimpleSend(t *testing.T) {
randomFill(buf)
proto := tcpip.NetworkProtocolNumber(rand.Intn(0x10000))
vv := buffer.NewVectorisedView(len(buf), []buffer.View{buf})
if err := c.ep.WritePacket(&r, &hdr, vv, proto); err != nil {
if err := c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), proto); err != nil {
t.Fatalf("WritePacket failed: %v", err)
}
@@ -330,7 +329,6 @@ func TestFillTxQueue(t *testing.T) {
}
buf := buffer.NewView(100)
vv := buffer.NewVectorisedView(len(buf), []buffer.View{buf})
// Each packet is uses no more than 40 bytes, so write that many packets
// until the tx queue if full.
@@ -338,7 +336,7 @@ func TestFillTxQueue(t *testing.T) {
for i := queuePipeSize / 40; i > 0; i-- {
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
if err := c.ep.WritePacket(&r, &hdr, vv, header.IPv4ProtocolNumber); err != nil {
if err := c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), header.IPv4ProtocolNumber); err != nil {
t.Fatalf("WritePacket failed unexpectedly: %v", err)
}
@@ -353,7 +351,7 @@ func TestFillTxQueue(t *testing.T) {
// Next attempt to write must fail.
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, &hdr, vv, header.IPv4ProtocolNumber); err != want {
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), header.IPv4ProtocolNumber); err != want {
t.Fatalf("WritePacket return unexpected result: got %v, want %v", err, want)
}
}
@@ -374,12 +372,11 @@ func TestFillTxQueueAfterBadCompletion(t *testing.T) {
}
buf := buffer.NewView(100)
vv := buffer.NewVectorisedView(len(buf), []buffer.View{buf})
// Send two packets so that the id slice has at least two slots.
for i := 2; i > 0; i-- {
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
if err := c.ep.WritePacket(&r, &hdr, vv, header.IPv4ProtocolNumber); err != nil {
if err := c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), header.IPv4ProtocolNumber); err != nil {
t.Fatalf("WritePacket failed unexpectedly: %v", err)
}
}
@@ -399,7 +396,7 @@ func TestFillTxQueueAfterBadCompletion(t *testing.T) {
ids := make(map[uint64]struct{})
for i := queuePipeSize / 40; i > 0; i-- {
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
if err := c.ep.WritePacket(&r, &hdr, vv, header.IPv4ProtocolNumber); err != nil {
if err := c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), header.IPv4ProtocolNumber); err != nil {
t.Fatalf("WritePacket failed unexpectedly: %v", err)
}
@@ -414,7 +411,7 @@ func TestFillTxQueueAfterBadCompletion(t *testing.T) {
// Next attempt to write must fail.
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, &hdr, vv, header.IPv4ProtocolNumber); err != want {
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), header.IPv4ProtocolNumber); err != want {
t.Fatalf("WritePacket return unexpected result: got %v, want %v", err, want)
}
}
@@ -431,14 +428,13 @@ func TestFillTxMemory(t *testing.T) {
}
buf := buffer.NewView(100)
vv := buffer.NewVectorisedView(len(buf), []buffer.View{buf})
// Each packet is uses up one buffer, so write as many as possible until
// we fill the memory.
ids := make(map[uint64]struct{})
for i := queueDataSize / bufferSize; i > 0; i-- {
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
if err := c.ep.WritePacket(&r, &hdr, vv, header.IPv4ProtocolNumber); err != nil {
if err := c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), header.IPv4ProtocolNumber); err != nil {
t.Fatalf("WritePacket failed unexpectedly: %v", err)
}
@@ -454,7 +450,7 @@ func TestFillTxMemory(t *testing.T) {
// Next attempt to write must fail.
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
err := c.ep.WritePacket(&r, &hdr, vv, header.IPv4ProtocolNumber)
err := c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), header.IPv4ProtocolNumber)
if want := tcpip.ErrWouldBlock; err != want {
t.Fatalf("WritePacket return unexpected result: got %v, want %v", err, want)
}
@@ -474,13 +470,12 @@ func TestFillTxMemoryWithMultiBuffer(t *testing.T) {
}
buf := buffer.NewView(100)
vv := buffer.NewVectorisedView(len(buf), []buffer.View{buf})
// Each packet is uses up one buffer, so write as many as possible
// until there is only one buffer left.
for i := queueDataSize/bufferSize - 1; i > 0; i-- {
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
if err := c.ep.WritePacket(&r, &hdr, vv, header.IPv4ProtocolNumber); err != nil {
if err := c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), header.IPv4ProtocolNumber); err != nil {
t.Fatalf("WritePacket failed unexpectedly: %v", err)
}
@@ -490,20 +485,26 @@ func TestFillTxMemoryWithMultiBuffer(t *testing.T) {
}
// Attempt to write a two-buffer packet. It must fail.
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
uu := buffer.NewVectorisedView(bufferSize, []buffer.View{buffer.NewView(bufferSize)})
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, &hdr, uu, header.IPv4ProtocolNumber); err != want {
t.Fatalf("WritePacket return unexpected result: got %v, want %v", err, want)
{
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
uu := buffer.NewView(bufferSize).ToVectorisedView()
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, &hdr, uu, header.IPv4ProtocolNumber); err != want {
t.Fatalf("WritePacket return unexpected result: got %v, want %v", err, want)
}
}
// Attempt to write the one-buffer packet again. It must succeed.
hdr = buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
if err := c.ep.WritePacket(&r, &hdr, vv, header.IPv4ProtocolNumber); err != nil {
t.Fatalf("WritePacket failed unexpectedly: %v", err)
{
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
if err := c.ep.WritePacket(&r, &hdr, buf.ToVectorisedView(), header.IPv4ProtocolNumber); err != nil {
t.Fatalf("WritePacket failed unexpectedly: %v", err)
}
}
}
func pollPull(t *testing.T, p *pipe.Rx, to <-chan time.Time, errStr string) []byte {
t.Helper()
for {
b := p.Pull()
if b != nil {
@@ -513,7 +514,7 @@ func pollPull(t *testing.T, p *pipe.Rx, to <-chan time.Time, errStr string) []by
select {
case <-time.After(10 * time.Millisecond):
case <-to:
t.Fatalf(errStr)
t.Fatal(errStr)
}
}
}
+1 -1
View File
@@ -116,7 +116,7 @@ func NewWithFile(lower tcpip.LinkEndpointID, file *os.File, snapLen uint32) (tcp
// DeliverNetworkPacket implements the stack.NetworkDispatcher interface. It is
// called by the link-layer endpoint being wrapped when a packet arrives, and
// logs the packet before forwarding to the actual dispatcher.
func (e *endpoint) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
func (e *endpoint) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
if atomic.LoadUint32(&LogPackets) == 1 && e.file == nil {
logPacket("recv", protocol, vv.First())
}
+1 -1
View File
@@ -51,7 +51,7 @@ func New(lower tcpip.LinkEndpointID) (tcpip.LinkEndpointID, *Endpoint) {
// It is called by the link-layer endpoint being wrapped when a packet arrives,
// and only forwards to the actual dispatcher if Wait or WaitDispatch haven't
// been called.
func (e *Endpoint) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
func (e *Endpoint) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
if !e.dispatchGate.Enter() {
return
}
+4 -4
View File
@@ -35,7 +35,7 @@ type countedEndpoint struct {
dispatcher stack.NetworkDispatcher
}
func (e *countedEndpoint) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) {
func (e *countedEndpoint) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) {
e.dispatchCount++
}
@@ -106,21 +106,21 @@ func TestWaitDispatch(t *testing.T) {
}
// Dispatch and check that it goes through.
ep.dispatcher.DeliverNetworkPacket(ep, "", 0, nil)
ep.dispatcher.DeliverNetworkPacket(ep, "", 0, buffer.VectorisedView{})
if want := 1; ep.dispatchCount != want {
t.Fatalf("Unexpected dispatchCount: got=%v, want=%v", ep.dispatchCount, want)
}
// Wait on writes, then try to dispatch. It must go through.
wep.WaitWrite()
ep.dispatcher.DeliverNetworkPacket(ep, "", 0, nil)
ep.dispatcher.DeliverNetworkPacket(ep, "", 0, buffer.VectorisedView{})
if want := 2; ep.dispatchCount != want {
t.Fatalf("Unexpected dispatchCount: got=%v, want=%v", ep.dispatchCount, want)
}
// Wait on dispatches, then try to dispatch. It must not go through.
wep.WaitDispatch()
ep.dispatcher.DeliverNetworkPacket(ep, "", 0, nil)
ep.dispatcher.DeliverNetworkPacket(ep, "", 0, buffer.VectorisedView{})
if want := 2; ep.dispatchCount != want {
t.Fatalf("Unexpected dispatchCount: got=%v, want=%v", ep.dispatchCount, want)
}
+1 -1
View File
@@ -83,7 +83,7 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload
return tcpip.ErrNotSupported
}
func (e *endpoint) HandlePacket(r *stack.Route, vv *buffer.VectorisedView) {
func (e *endpoint) HandlePacket(r *stack.Route, vv buffer.VectorisedView) {
v := vv.First()
h := header.ARP(v)
if !h.IsValid() {
+41 -41
View File
@@ -96,54 +96,54 @@ func TestDirectRequest(t *testing.T) {
copy(h.HardwareAddressSender(), senderMAC)
copy(h.ProtocolAddressSender(), senderIPv4)
// stackAddr1
copy(h.ProtocolAddressTarget(), stackAddr1)
vv := v.ToVectorisedView([1]buffer.View{})
c.linkEP.Inject(arp.ProtocolNumber, &vv)
pkt := <-c.linkEP.C
if pkt.Proto != arp.ProtocolNumber {
t.Fatalf("stackAddr1: expected ARP response, got network protocol number %v", pkt.Proto)
}
rep := header.ARP(pkt.Header)
if !rep.IsValid() {
t.Fatalf("stackAddr1: invalid ARP response len(pkt.Header)=%d", len(pkt.Header))
}
if tcpip.Address(rep.ProtocolAddressSender()) != stackAddr1 {
t.Errorf("stackAddr1: expected sender to be set")
}
if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != stackLinkAddr {
t.Errorf("stackAddr1: expected sender to be stackLinkAddr, got %q", got)
inject := func(addr tcpip.Address) {
copy(h.ProtocolAddressTarget(), addr)
c.linkEP.Inject(arp.ProtocolNumber, v.ToVectorisedView())
}
// stackAddr2
copy(h.ProtocolAddressTarget(), stackAddr2)
vv = v.ToVectorisedView([1]buffer.View{})
c.linkEP.Inject(arp.ProtocolNumber, &vv)
pkt = <-c.linkEP.C
if pkt.Proto != arp.ProtocolNumber {
t.Fatalf("stackAddr2: expected ARP response, got network protocol number %v", pkt.Proto)
}
rep = header.ARP(pkt.Header)
if !rep.IsValid() {
t.Fatalf("stackAddr2: invalid ARP response len(pkt.Header)=%d", len(pkt.Header))
}
if tcpip.Address(rep.ProtocolAddressSender()) != stackAddr2 {
t.Errorf("stackAddr2: expected sender to be set")
}
if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != stackLinkAddr {
t.Errorf("stackAddr2: expected sender to be stackLinkAddr, got %q", got)
inject(stackAddr1)
{
pkt := <-c.linkEP.C
if pkt.Proto != arp.ProtocolNumber {
t.Fatalf("stackAddr1: expected ARP response, got network protocol number %v", pkt.Proto)
}
rep := header.ARP(pkt.Header)
if !rep.IsValid() {
t.Fatalf("stackAddr1: invalid ARP response len(pkt.Header)=%d", len(pkt.Header))
}
if tcpip.Address(rep.ProtocolAddressSender()) != stackAddr1 {
t.Errorf("stackAddr1: expected sender to be set")
}
if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != stackLinkAddr {
t.Errorf("stackAddr1: expected sender to be stackLinkAddr, got %q", got)
}
}
// stackAddrBad
copy(h.ProtocolAddressTarget(), stackAddrBad)
vv = v.ToVectorisedView([1]buffer.View{})
c.linkEP.Inject(arp.ProtocolNumber, &vv)
inject(stackAddr2)
{
pkt := <-c.linkEP.C
if pkt.Proto != arp.ProtocolNumber {
t.Fatalf("stackAddr2: expected ARP response, got network protocol number %v", pkt.Proto)
}
rep := header.ARP(pkt.Header)
if !rep.IsValid() {
t.Fatalf("stackAddr2: invalid ARP response len(pkt.Header)=%d", len(pkt.Header))
}
if tcpip.Address(rep.ProtocolAddressSender()) != stackAddr2 {
t.Errorf("stackAddr2: expected sender to be set")
}
if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != stackLinkAddr {
t.Errorf("stackAddr2: expected sender to be stackLinkAddr, got %q", got)
}
}
inject(stackAddrBad)
select {
case pkt := <-c.linkEP.C:
t.Errorf("stackAddrBad: unexpected packet sent, Proto=%v", pkt.Proto)
case <-time.After(100 * time.Millisecond):
// Sleep tests are gross, but this will only
// potentially fail flakily if there's a bugj
// If there is no bug this will reliably succeed.
// Sleep tests are gross, but this will only potentially flake
// if there's a bug. If there is no bug this will reliably
// succeed.
}
}
+3 -3
View File
@@ -23,7 +23,7 @@ import (
type fragment struct {
offset uint16
vv *buffer.VectorisedView
vv buffer.VectorisedView
}
type fragHeap []fragment
@@ -60,7 +60,7 @@ func (h *fragHeap) reassemble() (buffer.VectorisedView, error) {
size := curr.vv.Size()
if curr.offset != 0 {
return buffer.NewVectorisedView(0, nil), fmt.Errorf("offset of the first packet is != 0 (%d)", curr.offset)
return buffer.VectorisedView{}, fmt.Errorf("offset of the first packet is != 0 (%d)", curr.offset)
}
for h.Len() > 0 {
@@ -68,7 +68,7 @@ func (h *fragHeap) reassemble() (buffer.VectorisedView, error) {
if int(curr.offset) < size {
curr.vv.TrimFront(size - int(curr.offset))
} else if int(curr.offset) > size {
return buffer.NewVectorisedView(0, nil), fmt.Errorf("packet has a hole, expected offset %d, got %d", size, curr.offset)
return buffer.VectorisedView{}, fmt.Errorf("packet has a hole, expected offset %d, got %d", size, curr.offset)
}
size += curr.vv.Size()
views = append(views, curr.vv.Views()...)
@@ -25,7 +25,7 @@ import (
var reassambleTestCases = []struct {
comment string
in []fragment
want *buffer.VectorisedView
want buffer.VectorisedView
}{
{
comment: "Non-overlapping in-order",
@@ -87,21 +87,25 @@ var reassambleTestCases = []struct {
func TestReassamble(t *testing.T) {
for _, c := range reassambleTestCases {
h := (fragHeap)(make([]fragment, 0, 8))
heap.Init(&h)
for _, f := range c.in {
heap.Push(&h, f)
}
got, _ := h.reassemble()
if !reflect.DeepEqual(got, *c.want) {
t.Errorf("Test \"%s\" reassembling failed. Got %v. Want %v", c.comment, got, *c.want)
}
t.Run(c.comment, func(t *testing.T) {
h := make(fragHeap, 0, 8)
heap.Init(&h)
for _, f := range c.in {
heap.Push(&h, f)
}
got, err := h.reassemble()
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, c.want) {
t.Errorf("got reassemble(%+v) = %v, want = %v", c.in, got, c.want)
}
})
}
}
func TestReassambleFailsForNonZeroOffset(t *testing.T) {
h := (fragHeap)(make([]fragment, 0, 8))
h := make(fragHeap, 0, 8)
heap.Init(&h)
heap.Push(&h, fragment{offset: 1, vv: vv(1, "0")})
_, err := h.reassemble()
@@ -111,7 +115,7 @@ func TestReassambleFailsForNonZeroOffset(t *testing.T) {
}
func TestReassambleFailsForHoles(t *testing.T) {
h := (fragHeap)(make([]fragment, 0, 8))
h := make(fragHeap, 0, 8)
heap.Init(&h)
heap.Push(&h, fragment{offset: 0, vv: vv(1, "0")})
heap.Push(&h, fragment{offset: 2, vv: vv(1, "1")})
@@ -82,7 +82,7 @@ func NewFragmentation(highMemoryLimit, lowMemoryLimit int, reassemblingTimeout t
// Process processes an incoming fragment beloning to an ID
// and returns a complete packet when all the packets belonging to that ID have been received.
func (f *Fragmentation) Process(id uint32, first, last uint16, more bool, vv *buffer.VectorisedView) (buffer.VectorisedView, bool) {
func (f *Fragmentation) Process(id uint32, first, last uint16, more bool, vv buffer.VectorisedView) (buffer.VectorisedView, bool) {
f.mu.Lock()
r, ok := f.reassemblers[id]
if ok && r.tooOld(f.timeout) {
@@ -23,19 +23,13 @@ import (
)
// vv is a helper to build VectorisedView from different strings.
func vv(size int, pieces ...string) *buffer.VectorisedView {
func vv(size int, pieces ...string) buffer.VectorisedView {
views := make([]buffer.View, len(pieces))
for i, p := range pieces {
views[i] = []byte(p)
}
vv := buffer.NewVectorisedView(size, views)
return &vv
}
func emptyVv() *buffer.VectorisedView {
vv := buffer.NewVectorisedView(0, nil)
return &vv
return buffer.NewVectorisedView(size, views)
}
type processInput struct {
@@ -43,11 +37,11 @@ type processInput struct {
first uint16
last uint16
more bool
vv *buffer.VectorisedView
vv buffer.VectorisedView
}
type processOutput struct {
vv *buffer.VectorisedView
vv buffer.VectorisedView
done bool
}
@@ -63,7 +57,7 @@ var processTestCases = []struct {
{id: 0, first: 2, last: 3, more: false, vv: vv(2, "23")},
},
out: []processOutput{
{vv: emptyVv(), done: false},
{vv: buffer.VectorisedView{}, done: false},
{vv: vv(4, "01", "23"), done: true},
},
},
@@ -76,8 +70,8 @@ var processTestCases = []struct {
{id: 0, first: 2, last: 3, more: false, vv: vv(2, "23")},
},
out: []processOutput{
{vv: emptyVv(), done: false},
{vv: emptyVv(), done: false},
{vv: buffer.VectorisedView{}, done: false},
{vv: buffer.VectorisedView{}, done: false},
{vv: vv(4, "ab", "cd"), done: true},
{vv: vv(4, "01", "23"), done: true},
},
@@ -86,26 +80,28 @@ var processTestCases = []struct {
func TestFragmentationProcess(t *testing.T) {
for _, c := range processTestCases {
f := NewFragmentation(1024, 512, DefaultReassembleTimeout)
for i, in := range c.in {
vv, done := f.Process(in.id, in.first, in.last, in.more, in.vv)
if !reflect.DeepEqual(vv, *(c.out[i].vv)) {
t.Errorf("Test \"%s\" Process() returned a wrong vv. Got %v. Want %v", c.comment, vv, *(c.out[i].vv))
}
if done != c.out[i].done {
t.Errorf("Test \"%s\" Process() returned a wrong done. Got %t. Want %t", c.comment, done, c.out[i].done)
}
if c.out[i].done {
if _, ok := f.reassemblers[in.id]; ok {
t.Errorf("Test \"%s\" Process() didn't remove buffer from reassemblers.", c.comment)
t.Run(c.comment, func(t *testing.T) {
f := NewFragmentation(1024, 512, DefaultReassembleTimeout)
for i, in := range c.in {
vv, done := f.Process(in.id, in.first, in.last, in.more, in.vv)
if !reflect.DeepEqual(vv, c.out[i].vv) {
t.Errorf("got Process(%d) = %+v, want = %+v", i, vv, c.out[i].vv)
}
for n := f.rList.Front(); n != nil; n = n.Next() {
if n.id == in.id {
t.Errorf("Test \"%s\" Process() didn't remove buffer from rList.", c.comment)
if done != c.out[i].done {
t.Errorf("got Process(%d) = %+v, want = %+v", i, done, c.out[i].done)
}
if c.out[i].done {
if _, ok := f.reassemblers[in.id]; ok {
t.Errorf("Process(%d) did not remove buffer from reassemblers", i)
}
for n := f.rList.Front(); n != nil; n = n.Next() {
if n.id == in.id {
t.Errorf("Process(%d) did not remove buffer from rList", i)
}
}
}
}
}
})
}
}
@@ -161,16 +157,3 @@ func TestMemoryLimitsIgnoresDuplicates(t *testing.T) {
t.Errorf("Wrong size, duplicates are not handled correctly: got=%d, want=%d.", got, want)
}
}
func TestFragmentationViewsDoNotEscape(t *testing.T) {
f := NewFragmentation(1024, 512, DefaultReassembleTimeout)
in := vv(2, "0", "1")
f.Process(0, 0, 1, true, in)
// Modify input view.
in.RemoveFirst()
got, _ := f.Process(0, 2, 2, false, vv(1, "2"))
want := vv(3, "0", "1", "2")
if !reflect.DeepEqual(got, *want) {
t.Errorf("Process() returned a wrong vv. Got %v. Want %v", got, *want)
}
}

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