summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/transport/tcp
diff options
context:
space:
mode:
authorTamir Duberstein <tamird@google.com>2018-08-27 15:28:38 -0700
committerShentubot <shentubot@google.com>2018-08-27 15:29:55 -0700
commit0923bcf06bffe0216cd685f49e83a07201d48cc3 (patch)
treebe364ad4d00bf8952af309a1b4ed870392bf82ad /pkg/tcpip/transport/tcp
parent0b3bfe2ea30d491a6533f8ee74eb6e3cea707f06 (diff)
Add various statistics
PiperOrigin-RevId: 210442599 Change-Id: I9498351f461dc69c77b7f815d526c5693bec8e4a
Diffstat (limited to 'pkg/tcpip/transport/tcp')
-rw-r--r--pkg/tcpip/transport/tcp/connect.go10
-rw-r--r--pkg/tcpip/transport/tcp/endpoint.go22
-rw-r--r--pkg/tcpip/transport/tcp/tcp_test.go428
-rw-r--r--pkg/tcpip/transport/tcp/tcp_timestamp_test.go3
-rw-r--r--pkg/tcpip/transport/tcp/testing/context/context.go19
5 files changed, 369 insertions, 113 deletions
diff --git a/pkg/tcpip/transport/tcp/connect.go b/pkg/tcpip/transport/tcp/connect.go
index 58d7942f3..14282d399 100644
--- a/pkg/tcpip/transport/tcp/connect.go
+++ b/pkg/tcpip/transport/tcp/connect.go
@@ -604,6 +604,11 @@ func sendTCPWithOptions(r *stack.Route, id stack.TransportEndpointID, data buffe
tcp.SetChecksum(^tcp.CalculateChecksum(xsum, length))
}
+ r.Stats().TCP.SegmentsSent.Increment()
+ if (flags & flagRst) != 0 {
+ r.Stats().TCP.ResetsSent.Increment()
+ }
+
return r.WritePacket(&hdr, data, ProtocolNumber)
}
@@ -641,6 +646,11 @@ func sendTCP(r *stack.Route, id stack.TransportEndpointID, data buffer.View, fla
tcp.SetChecksum(^tcp.CalculateChecksum(xsum, length))
}
+ r.Stats().TCP.SegmentsSent.Increment()
+ if (flags & flagRst) != 0 {
+ r.Stats().TCP.ResetsSent.Increment()
+ }
+
return r.WritePacket(&hdr, data, ProtocolNumber)
}
diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go
index bdcba39c6..cbbbbc084 100644
--- a/pkg/tcpip/transport/tcp/endpoint.go
+++ b/pkg/tcpip/transport/tcp/endpoint.go
@@ -829,9 +829,14 @@ func (e *endpoint) Connect(addr tcpip.FullAddress) *tcpip.Error {
// created (so no new handshaking is done); for stack-accepted connections not
// yet accepted by the app, they are restored without running the main goroutine
// here.
-func (e *endpoint) connect(addr tcpip.FullAddress, handshake bool, run bool) *tcpip.Error {
+func (e *endpoint) connect(addr tcpip.FullAddress, handshake bool, run bool) (err *tcpip.Error) {
e.mu.Lock()
defer e.mu.Unlock()
+ defer func() {
+ if err != nil && !err.IgnoreStats() {
+ e.stack.Stats().TCP.FailedConnectionAttempts.Increment()
+ }
+ }()
connectingAddr := addr.Addr
@@ -960,6 +965,7 @@ func (e *endpoint) connect(addr tcpip.FullAddress, handshake bool, run bool) *tc
if run {
e.workerRunning = true
+ e.stack.Stats().TCP.ActiveConnectionOpenings.Increment()
go e.protocolMainLoop(handshake) // S/R-SAFE: will be drained before save.
}
@@ -1032,9 +1038,14 @@ func (e *endpoint) Shutdown(flags tcpip.ShutdownFlags) *tcpip.Error {
// Listen puts the endpoint in "listen" mode, which allows it to accept
// new connections.
-func (e *endpoint) Listen(backlog int) *tcpip.Error {
+func (e *endpoint) Listen(backlog int) (err *tcpip.Error) {
e.mu.Lock()
defer e.mu.Unlock()
+ defer func() {
+ if err != nil && !err.IgnoreStats() {
+ e.stack.Stats().TCP.FailedConnectionAttempts.Increment()
+ }
+ }()
// Allow the backlog to be adjusted if the endpoint is not shutting down.
// When the endpoint shuts down, it sets workerCleanup to true, and from
@@ -1075,6 +1086,7 @@ func (e *endpoint) Listen(backlog int) *tcpip.Error {
}
e.workerRunning = true
+ e.stack.Stats().TCP.PassiveConnectionOpenings.Increment()
go e.protocolListenLoop( // S/R-SAFE: drained on save.
seqnum.Size(e.receiveBufferAvailable()))
@@ -1226,10 +1238,16 @@ func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv
s := newSegment(r, id, vv)
if !s.parse() {
e.stack.Stats().MalformedRcvdPackets.Increment()
+ e.stack.Stats().TCP.InvalidSegmentsReceived.Increment()
s.decRef()
return
}
+ e.stack.Stats().TCP.ValidSegmentsReceived.Increment()
+ if (s.flags & flagRst) != 0 {
+ e.stack.Stats().TCP.ResetsReceived.Increment()
+ }
+
// Send packet to worker goroutine.
if e.segmentQueue.enqueue(s) {
e.newSegmentWaker.Assert()
diff --git a/pkg/tcpip/transport/tcp/tcp_test.go b/pkg/tcpip/transport/tcp/tcp_test.go
index 74318c012..71d70a597 100644
--- a/pkg/tcpip/transport/tcp/tcp_test.go
+++ b/pkg/tcpip/transport/tcp/tcp_test.go
@@ -62,7 +62,7 @@ func TestGiveUpConnect(t *testing.T) {
defer wq.EventUnregister(&waitEntry)
if err := ep.Connect(tcpip.FullAddress{Addr: context.TestAddr, Port: context.TestPort}); err != tcpip.ErrConnectStarted {
- t.Fatalf("Unexpected return value from Connect: %v", err)
+ t.Fatalf("got ep.Connect(...) = %v, want = %v", err, tcpip.ErrConnectStarted)
}
// Close the connection, wait for completion.
@@ -75,6 +75,187 @@ func TestGiveUpConnect(t *testing.T) {
}
}
+func TestConnectIncrementActiveConnection(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+
+ stats := c.Stack().Stats()
+ want := stats.TCP.ActiveConnectionOpenings.Value() + 1
+
+ c.CreateConnected(789, 30000, nil)
+ if got := stats.TCP.ActiveConnectionOpenings.Value(); got != want {
+ t.Errorf("got stats.TCP.ActtiveConnectionOpenings.Value() = %v, want = %v", got, want)
+ }
+}
+
+func TestConnectDoesNotIncrementFailedConnectionAttempts(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+
+ stats := c.Stack().Stats()
+ want := stats.TCP.FailedConnectionAttempts.Value()
+
+ c.CreateConnected(789, 30000, nil)
+ if got := stats.TCP.FailedConnectionAttempts.Value(); got != want {
+ t.Errorf("got stats.TCP.FailedConnectionOpenings.Value() = %v, want = %v", got, want)
+ }
+}
+
+func TestActiveFailedConnectionAttemptIncrement(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+
+ stats := c.Stack().Stats()
+ ep, err := c.Stack().NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ)
+ if err != nil {
+ t.Fatalf("NewEndpoint failed: %v", err)
+ }
+ c.EP = ep
+ want := stats.TCP.FailedConnectionAttempts.Value() + 1
+
+ if err := c.EP.Connect(tcpip.FullAddress{NIC: 2, Addr: context.TestAddr, Port: context.TestPort}); err != tcpip.ErrNoRoute {
+ t.Errorf("got c.EP.Connect(...) = %v, want = %v", err, tcpip.ErrNoRoute)
+ }
+
+ if got := stats.TCP.FailedConnectionAttempts.Value(); got != want {
+ t.Errorf("got stats.TCP.FailedConnectionAttempts.Value() = %v, want = %v", got, want)
+ }
+}
+
+func TestPassiveConnectionAttemptIncrement(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+
+ stats := c.Stack().Stats()
+ want := stats.TCP.PassiveConnectionOpenings.Value() + 1
+ ep, err := c.Stack().NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ)
+ if err != nil {
+ t.Fatalf("NewEndpoint failed: %v", err)
+ }
+
+ if err := ep.Bind(tcpip.FullAddress{Addr: context.StackAddr, Port: context.StackPort}, nil); err != nil {
+ t.Fatalf("Bind failed: %v", err)
+ }
+ if err := ep.Listen(1); err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ }
+
+ if got := stats.TCP.PassiveConnectionOpenings.Value(); got != want {
+ t.Errorf("got stats.TCP.PassiveConnectionOpenings.Value() = %v, want = %v", got, want)
+ }
+}
+
+func TestPassiveFailedConnectionAttemptIncrement(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+
+ stats := c.Stack().Stats()
+ ep, err := c.Stack().NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ)
+ if err != nil {
+ t.Fatalf("NewEndpoint failed: %v", err)
+ }
+ c.EP = ep
+ want := stats.TCP.FailedConnectionAttempts.Value() + 1
+
+ if err := ep.Listen(1); err != tcpip.ErrInvalidEndpointState {
+ t.Errorf("got ep.Listen(1) = %v, want = %v", err, tcpip.ErrInvalidEndpointState)
+ }
+
+ if got := stats.TCP.FailedConnectionAttempts.Value(); got != want {
+ t.Errorf("got stats.TCP.FailedConnectionAttempts.Value() = %v, want = %v", got, want)
+ }
+}
+
+func TestTCPSegmentsSentIncrement(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+
+ stats := c.Stack().Stats()
+ // SYN and ACK
+ want := stats.TCP.SegmentsSent.Value() + 2
+ c.CreateConnected(789, 30000, nil)
+
+ if got := stats.TCP.SegmentsSent.Value(); got != want {
+ t.Errorf("got stats.TCP.SegmentsSent.Value() = %v, want = %v", got, want)
+ }
+}
+
+func TestTCPResetsSentIncrement(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+ stats := c.Stack().Stats()
+ wq := &waiter.Queue{}
+ ep, err := c.Stack().NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, wq)
+ if err != nil {
+ t.Fatalf("NewEndpoint failed: %v", err)
+ }
+ want := stats.TCP.SegmentsSent.Value() + 1
+
+ if err := ep.Bind(tcpip.FullAddress{Port: context.StackPort}, nil); err != nil {
+ t.Fatalf("Bind failed: %v", err)
+ }
+
+ if err := ep.Listen(10); err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ }
+
+ // Send a SYN request.
+ iss := seqnum.Value(789)
+ c.SendPacket(nil, &context.Headers{
+ SrcPort: context.TestPort,
+ DstPort: context.StackPort,
+ Flags: header.TCPFlagSyn,
+ SeqNum: iss,
+ })
+
+ // Receive the SYN-ACK reply.
+ b := c.GetPacket()
+ tcp := header.TCP(header.IPv4(b).Payload())
+ c.IRS = seqnum.Value(tcp.SequenceNumber())
+
+ ackHeaders := &context.Headers{
+ SrcPort: context.TestPort,
+ DstPort: context.StackPort,
+ Flags: header.TCPFlagAck,
+ SeqNum: iss + 1,
+ // If the AckNum is not the increment of the last sequence number, a RST
+ // segment is sent back in response.
+ AckNum: c.IRS + 2,
+ }
+
+ // Send ACK.
+ c.SendPacket(nil, ackHeaders)
+
+ c.GetPacket()
+ if got := stats.TCP.ResetsSent.Value(); got != want {
+ t.Errorf("got stats.TCP.ResetsSent.Value() = %v, want = %v", got, want)
+ }
+}
+
+func TestTCPResetsReceivedIncrement(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+
+ stats := c.Stack().Stats()
+ want := stats.TCP.ResetsReceived.Value() + 1
+ ackNum := seqnum.Value(789)
+ rcvWnd := seqnum.Size(30000)
+ c.CreateConnected(ackNum, rcvWnd, nil)
+
+ c.SendPacket(nil, &context.Headers{
+ SrcPort: context.TestPort,
+ DstPort: c.Port,
+ SeqNum: c.IRS.Add(2),
+ AckNum: ackNum.Add(2),
+ RcvWnd: rcvWnd,
+ Flags: header.TCPFlagRst,
+ })
+
+ if got := stats.TCP.ResetsReceived.Value(); got != want {
+ t.Errorf("got stats.TCP.ResetsReceived.Value() = %v, want = %v", got, want)
+ }
+}
+
func TestActiveHandshake(t *testing.T) {
c := context.New(t, defaultMTU)
defer c.Cleanup()
@@ -159,7 +340,7 @@ func TestSimpleReceive(t *testing.T) {
defer c.WQ.EventUnregister(&we)
if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrWouldBlock)
}
data := []byte{1, 2, 3}
@@ -182,11 +363,11 @@ func TestSimpleReceive(t *testing.T) {
// Receive data.
v, _, err := c.EP.Read(nil)
if err != nil {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("Read failed: %v", err)
}
- if bytes.Compare(data, v) != 0 {
- t.Fatalf("Data is different: expected %v, got %v", data, v)
+ if !bytes.Equal(data, v) {
+ t.Fatalf("got data = %v, want = %v", v, data)
}
// Check that ACK is received.
@@ -211,7 +392,7 @@ func TestOutOfOrderReceive(t *testing.T) {
defer c.WQ.EventUnregister(&we)
if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrWouldBlock)
}
// Send second half of data first, with seqnum 3 ahead of expected.
@@ -238,7 +419,7 @@ func TestOutOfOrderReceive(t *testing.T) {
// Wait 200ms and check that no data has been received.
time.Sleep(200 * time.Millisecond)
if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrWouldBlock)
}
// Send the first 3 bytes now.
@@ -265,15 +446,15 @@ func TestOutOfOrderReceive(t *testing.T) {
}
continue
}
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("Read failed: %v", err)
}
read = append(read, v...)
}
// Check that we received the data in proper order.
- if bytes.Compare(data, read) != 0 {
- t.Fatalf("Data is different: expected %v, got %v", data, read)
+ if !bytes.Equal(data, read) {
+ t.Fatalf("got data = %v, want = %v", read, data)
}
// Check that the whole data is acknowledged.
@@ -296,7 +477,7 @@ func TestOutOfOrderFlood(t *testing.T) {
c.CreateConnected(789, 30000, &opt)
if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrWouldBlock)
}
// Send 100 packets before the actual one that is expected.
@@ -373,7 +554,7 @@ func TestRstOnCloseWithUnreadData(t *testing.T) {
defer c.WQ.EventUnregister(&we)
if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrWouldBlock)
}
data := []byte{1, 2, 3}
@@ -438,7 +619,7 @@ func TestRstOnCloseWithUnreadDataFinConvertRst(t *testing.T) {
defer c.WQ.EventUnregister(&we)
if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrWouldBlock)
}
data := []byte{1, 2, 3}
@@ -517,7 +698,7 @@ func TestFullWindowReceive(t *testing.T) {
_, _, err := c.EP.Read(nil)
if err != tcpip.ErrWouldBlock {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("Read failed: %v", err)
}
// Fill up the window.
@@ -552,11 +733,11 @@ func TestFullWindowReceive(t *testing.T) {
// Receive data and check it.
v, _, err := c.EP.Read(nil)
if err != nil {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("Read failed: %v", err)
}
- if bytes.Compare(data, v) != 0 {
- t.Fatalf("Data is different: expected %v, got %v", data, v)
+ if !bytes.Equal(data, v) {
+ t.Fatalf("got data = %v, want = %v", v, data)
}
// Check that we get an ACK for the newly non-zero window.
@@ -588,9 +769,8 @@ func TestNoWindowShrinking(t *testing.T) {
c.WQ.EventRegister(&we, waiter.EventIn)
defer c.WQ.EventUnregister(&we)
- _, _, err := c.EP.Read(nil)
- if err != tcpip.ErrWouldBlock {
- t.Fatalf("Unexpected error from Read: %v", err)
+ if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrWouldBlock)
}
// Send 3 bytes, check that the peer acknowledges them.
@@ -654,14 +834,14 @@ func TestNoWindowShrinking(t *testing.T) {
for len(read) < len(data) {
v, _, err := c.EP.Read(nil)
if err != nil {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("Read failed: %v", err)
}
read = append(read, v...)
}
- if bytes.Compare(data, read) != 0 {
- t.Fatalf("Data is different: expected %v, got %v", data, read)
+ if !bytes.Equal(data, read) {
+ t.Fatalf("got data = %v, want = %v", read, data)
}
// Check that we get an ACK for the newly non-zero window, which is the
@@ -688,7 +868,7 @@ func TestSimpleSend(t *testing.T) {
copy(view, data)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Check that data is received.
@@ -703,8 +883,8 @@ func TestSimpleSend(t *testing.T) {
),
)
- if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; bytes.Compare(data, p) != 0 {
- t.Fatalf("Data is different: expected %v, got %v", data, p)
+ if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) {
+ t.Fatalf("got data = %v, want = %v", p, data)
}
// Acknowledge the data.
@@ -730,7 +910,7 @@ func TestZeroWindowSend(t *testing.T) {
_, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{})
if err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Since the window is currently zero, check that no packet is received.
@@ -758,8 +938,8 @@ func TestZeroWindowSend(t *testing.T) {
),
)
- if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; bytes.Compare(data, p) != 0 {
- t.Fatalf("Data is different: expected %v, got %v", data, p)
+ if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) {
+ t.Fatalf("got data = %v, want = %v", p, data)
}
// Acknowledge the data.
@@ -790,7 +970,7 @@ func TestScaledWindowConnect(t *testing.T) {
copy(view, data)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Check that data is received, and that advertised window is 0xbfff,
@@ -823,7 +1003,7 @@ func TestNonScaledWindowConnect(t *testing.T) {
copy(view, data)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Check that data is received, and that advertised window is 0xffff,
@@ -896,7 +1076,7 @@ func TestScaledWindowAccept(t *testing.T) {
copy(view, data)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Check that data is received, and that advertised window is 0xbfff,
@@ -969,7 +1149,7 @@ func TestNonScaledWindowAccept(t *testing.T) {
copy(view, data)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Check that data is received, and that advertised window is 0xffff,
@@ -1057,7 +1237,7 @@ func TestZeroScaledWindowReceive(t *testing.T) {
// Read some data. An ack should be sent in response to that.
v, _, err := c.EP.Read(nil)
if err != nil {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("Read failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -1084,7 +1264,7 @@ func testBrokenUpWrite(t *testing.T, c *context.Context, maxPayload int) {
copy(view, data)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Check that data is received in chunks.
@@ -1105,8 +1285,8 @@ func testBrokenUpWrite(t *testing.T, c *context.Context, maxPayload int) {
)
pdata := data[bytesReceived : bytesReceived+payloadLen]
- if p := tcp.Payload(); bytes.Compare(pdata, p) != 0 {
- t.Fatalf("Data is different: expected %v, got %v", pdata, p)
+ if p := tcp.Payload(); !bytes.Equal(pdata, p) {
+ t.Fatalf("got data = %v, want = %v", p, pdata)
}
bytesReceived += payloadLen
var options []byte
@@ -1325,9 +1505,8 @@ func TestSynOptionsOnActiveConnect(t *testing.T) {
c.WQ.EventRegister(&we, waiter.EventOut)
defer c.WQ.EventUnregister(&we)
- err = c.EP.Connect(tcpip.FullAddress{Addr: context.TestAddr, Port: context.TestPort})
- if err != tcpip.ErrConnectStarted {
- t.Fatalf("Unexpected return value from Connect: %v", err)
+ if err := c.EP.Connect(tcpip.FullAddress{Addr: context.TestAddr, Port: context.TestPort}); err != tcpip.ErrConnectStarted {
+ t.Fatalf("got c.EP.Connect(...) = %v, want = %v", err, tcpip.ErrConnectStarted)
}
// Receive SYN packet.
@@ -1380,9 +1559,8 @@ func TestSynOptionsOnActiveConnect(t *testing.T) {
// Wait for connection to be established.
select {
case <-ch:
- err = c.EP.GetSockOpt(tcpip.ErrorOption{})
- if err != nil {
- t.Fatalf("Unexpected error when connecting: %v", err)
+ if err := c.EP.GetSockOpt(tcpip.ErrorOption{}); err != nil {
+ t.Fatalf("GetSockOpt failed: %v", err)
}
case <-time.After(1 * time.Second):
t.Fatalf("Timed out waiting for connection")
@@ -1439,8 +1617,6 @@ func TestReceiveOnResetConnection(t *testing.T) {
loop:
for {
switch _, _, err := c.EP.Read(nil); err {
- case nil:
- t.Fatalf("Unexpected success.")
case tcpip.ErrWouldBlock:
select {
case <-ch:
@@ -1450,7 +1626,7 @@ loop:
case tcpip.ErrConnectionReset:
break loop
default:
- t.Fatalf("Unexpected error: want %v, got %v", tcpip.ErrConnectionReset, err)
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrConnectionReset)
}
}
}
@@ -1475,9 +1651,8 @@ func TestSendOnResetConnection(t *testing.T) {
// Try to write.
view := buffer.NewView(10)
- _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{})
- if err != tcpip.ErrConnectionReset {
- t.Fatalf("Unexpected error from Write: want %v, got %v", tcpip.ErrConnectionReset, err)
+ if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != tcpip.ErrConnectionReset {
+ t.Fatalf("got c.EP.Write(...) = %v, want = %v", err, tcpip.ErrConnectionReset)
}
}
@@ -1489,7 +1664,7 @@ func TestFinImmediately(t *testing.T) {
// Shutdown immediately, check that we get a FIN.
if err := c.EP.Shutdown(tcpip.ShutdownWrite); err != nil {
- t.Fatalf("Unexpected error from Shutdown: %v", err)
+ t.Fatalf("Shutdown failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -1532,7 +1707,7 @@ func TestFinRetransmit(t *testing.T) {
// Shutdown immediately, check that we get a FIN.
if err := c.EP.Shutdown(tcpip.ShutdownWrite); err != nil {
- t.Fatalf("Unexpected error from Shutdown: %v", err)
+ t.Fatalf("Shutdown failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -1587,7 +1762,7 @@ func TestFinWithNoPendingData(t *testing.T) {
// Write something out, and have it acknowledged.
view := buffer.NewView(10)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
next := uint32(c.IRS) + 1
@@ -1613,7 +1788,7 @@ func TestFinWithNoPendingData(t *testing.T) {
// Shutdown, check that we get a FIN.
if err := c.EP.Shutdown(tcpip.ShutdownWrite); err != nil {
- t.Fatalf("Unexpected error from Shutdown: %v", err)
+ t.Fatalf("Shutdown failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -1660,7 +1835,7 @@ func TestFinWithPendingDataCwndFull(t *testing.T) {
view := buffer.NewView(10)
for i := tcp.InitialCwnd; i > 0; i-- {
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
}
@@ -1682,7 +1857,7 @@ func TestFinWithPendingDataCwndFull(t *testing.T) {
// because the congestion window doesn't allow it. Wait until a
// retransmit is received.
if err := c.EP.Shutdown(tcpip.ShutdownWrite); err != nil {
- t.Fatalf("Unexpected error from Shutdown: %v", err)
+ t.Fatalf("Shutdown failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -1746,7 +1921,7 @@ func TestFinWithPendingData(t *testing.T) {
// Write something out, and acknowledge it to get cwnd to 2.
view := buffer.NewView(10)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
next := uint32(c.IRS) + 1
@@ -1772,7 +1947,7 @@ func TestFinWithPendingData(t *testing.T) {
// Write new data, but don't acknowledge it.
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -1788,7 +1963,7 @@ func TestFinWithPendingData(t *testing.T) {
// Shutdown the connection, check that we do get a FIN.
if err := c.EP.Shutdown(tcpip.ShutdownWrite); err != nil {
- t.Fatalf("Unexpected error from Shutdown: %v", err)
+ t.Fatalf("Shutdown failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -1833,7 +2008,7 @@ func TestFinWithPartialAck(t *testing.T) {
// FIN from the test side.
view := buffer.NewView(10)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
next := uint32(c.IRS) + 1
@@ -1870,7 +2045,7 @@ func TestFinWithPartialAck(t *testing.T) {
// Write new data, but don't acknowledge it.
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -1886,7 +2061,7 @@ func TestFinWithPartialAck(t *testing.T) {
// Shutdown the connection, check that we do get a FIN.
if err := c.EP.Shutdown(tcpip.ShutdownWrite); err != nil {
- t.Fatalf("Unexpected error from Shutdown: %v", err)
+ t.Fatalf("Shutdown failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -1940,7 +2115,7 @@ func TestExponentialIncreaseDuringSlowStart(t *testing.T) {
// Write all the data in one shot. Packets will only be written at the
// MTU size though.
if _, err := c.EP.Write(tcpip.SlicePayload(data), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
expected := tcp.InitialCwnd
@@ -1982,7 +2157,7 @@ func TestCongestionAvoidance(t *testing.T) {
// Write all the data in one shot. Packets will only be written at the
// MTU size though.
if _, err := c.EP.Write(tcpip.SlicePayload(data), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Do slow start for a few iterations.
@@ -2087,7 +2262,7 @@ func TestCubicCongestionAvoidance(t *testing.T) {
// Write all the data in one shot. Packets will only be written at the
// MTU size though.
if _, err := c.EP.Write(tcpip.SlicePayload(data), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Do slow start for a few iterations.
@@ -2157,18 +2332,18 @@ func TestCubicCongestionAvoidance(t *testing.T) {
// If our estimate was correct there should be no more pending packets.
// We attempt to read a packet a few times with a short sleep in between
// to ensure that we don't see the sender send any unexpected packets.
- packetsUnexpected := 0
+ unexpectedPackets := 0
for {
gotPacket := c.ReceiveNonBlockingAndCheckPacket(data, bytesRead, maxPayload)
if !gotPacket {
break
}
bytesRead += maxPayload
- packetsUnexpected++
+ unexpectedPackets++
time.Sleep(1 * time.Millisecond)
}
- if packetsUnexpected != 0 {
- t.Fatalf("received %d unexpected packets for iteration %d", packetsUnexpected, i)
+ if unexpectedPackets != 0 {
+ t.Fatalf("received %d unexpected packets for iteration %d", unexpectedPackets, i)
}
// Check we don't receive any more packets on this iteration.
// The timeout can't be too high or we'll trigger a timeout.
@@ -2195,7 +2370,7 @@ func TestFastRecovery(t *testing.T) {
// Write all the data in one shot. Packets will only be written at the
// MTU size though.
if _, err := c.EP.Write(tcpip.SlicePayload(data), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Do slow start for a few iterations.
@@ -2327,11 +2502,11 @@ func TestRetransmit(t *testing.T) {
// MTU size though.
half := data[:len(data)/2]
if _, err := c.EP.Write(tcpip.SlicePayload(half), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
half = data[len(data)/2:]
if _, err := c.EP.Write(tcpip.SlicePayload(half), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Do slow start for a few iterations.
@@ -2429,7 +2604,7 @@ func scaledSendWindow(t *testing.T, scale uint8) {
// Send some data. Check that it's capped by the window size.
view := buffer.NewView(65535)
if _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
- t.Fatalf("Unexpected error from Write: %v", err)
+ t.Fatalf("Write failed: %v", err)
}
// Check that only data that fits in the scaled window is sent.
@@ -2458,6 +2633,52 @@ func TestScaledSendWindow(t *testing.T) {
}
}
+func TestReceivedValidSegmentCountIncrement(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+ c.CreateConnected(789, 30000, nil)
+ stats := c.Stack().Stats()
+ want := stats.TCP.ValidSegmentsReceived.Value() + 1
+
+ c.SendPacket(nil, &context.Headers{
+ SrcPort: context.TestPort,
+ DstPort: c.Port,
+ Flags: header.TCPFlagAck,
+ SeqNum: seqnum.Value(790),
+ AckNum: c.IRS.Add(1),
+ RcvWnd: 30000,
+ })
+
+ if got := stats.TCP.ValidSegmentsReceived.Value(); got != want {
+ t.Errorf("got stats.TCP.ValidSegmentsReceived.Value() = %v, want = %v", got, want)
+ }
+}
+
+func TestReceivedInvalidSegmentCountIncrement(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+ c.CreateConnected(789, 30000, nil)
+ stats := c.Stack().Stats()
+ want := stats.TCP.InvalidSegmentsReceived.Value() + 1
+ vv := c.BuildSegment(nil, &context.Headers{
+ SrcPort: context.TestPort,
+ DstPort: c.Port,
+ Flags: header.TCPFlagAck,
+ SeqNum: seqnum.Value(790),
+ AckNum: c.IRS.Add(1),
+ RcvWnd: 30000,
+ })
+ tcpbuf := vv.ByteSlice()[0][header.IPv4MinimumSize:]
+ // 12 is the TCP header data offset.
+ tcpbuf[12] = ((header.TCPMinimumSize - 1) / 4) << 4
+
+ c.SendSegment(&vv)
+
+ if got := stats.TCP.InvalidSegmentsReceived.Value(); got != want {
+ t.Errorf("got stats.TCP.InvalidSegmentsReceived.Value() = %v, want = %v", got, want)
+ }
+}
+
func TestReceivedSegmentQueuing(t *testing.T) {
// This test sends 200 segments containing a few bytes each to an
// endpoint and checks that they're all received and acknowledged by
@@ -2519,12 +2740,12 @@ func TestReadAfterClosedState(t *testing.T) {
defer c.WQ.EventUnregister(&we)
if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrWouldBlock)
}
// Shutdown immediately for write, check that we get a FIN.
if err := c.EP.Shutdown(tcpip.ShutdownWrite); err != nil {
- t.Fatalf("Unexpected error from Shutdown: %v", err)
+ t.Fatalf("Shutdown failed: %v", err)
}
checker.IPv4(t, c.GetPacket(),
@@ -2572,32 +2793,32 @@ func TestReadAfterClosedState(t *testing.T) {
peekBuf := make([]byte, 10)
n, _, err := c.EP.Peek([][]byte{peekBuf})
if err != nil {
- t.Fatalf("Unexpected error from Peek: %v", err)
+ t.Fatalf("Peek failed: %v", err)
}
peekBuf = peekBuf[:n]
- if bytes.Compare(data, peekBuf) != 0 {
- t.Fatalf("Data is different: expected %v, got %v", data, peekBuf)
+ if !bytes.Equal(data, peekBuf) {
+ t.Fatalf("got data = %v, want = %v", peekBuf, data)
}
// Receive data.
v, _, err := c.EP.Read(nil)
if err != nil {
- t.Fatalf("Unexpected error from Read: %v", err)
+ t.Fatalf("Read failed: %v", err)
}
- if bytes.Compare(data, v) != 0 {
- t.Fatalf("Data is different: expected %v, got %v", data, v)
+ if !bytes.Equal(data, v) {
+ t.Fatalf("got data = %v, want = %v", v, data)
}
// Now that we drained the queue, check that functions fail with the
// right error code.
if _, _, err := c.EP.Read(nil); err != tcpip.ErrClosedForReceive {
- t.Fatalf("Unexpected return from Read: got %v, want %v", err, tcpip.ErrClosedForReceive)
+ t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrClosedForReceive)
}
if _, _, err := c.EP.Peek([][]byte{peekBuf}); err != tcpip.ErrClosedForReceive {
- t.Fatalf("Unexpected return from Peek: got %v, want %v", err, tcpip.ErrClosedForReceive)
+ t.Fatalf("got c.EP.Peek(...) = %v, want = %v", err, tcpip.ErrClosedForReceive)
}
}
@@ -2635,9 +2856,8 @@ func TestReusePort(t *testing.T) {
if err := c.EP.Bind(tcpip.FullAddress{Port: context.StackPort}, nil); err != nil {
t.Fatalf("Bind failed: %v", err)
}
- err = c.EP.Connect(tcpip.FullAddress{Addr: context.TestAddr, Port: context.TestPort})
- if err != tcpip.ErrConnectStarted {
- t.Fatalf("Unexpected return value from Connect: %v", err)
+ if err := c.EP.Connect(tcpip.FullAddress{Addr: context.TestAddr, Port: context.TestPort}); err != tcpip.ErrConnectStarted {
+ t.Fatalf("got c.EP.Connect(...) = %v, want = %v", err, tcpip.ErrConnectStarted)
}
c.EP.Close()
@@ -2658,8 +2878,7 @@ func TestReusePort(t *testing.T) {
if err := c.EP.Bind(tcpip.FullAddress{Port: context.StackPort}, nil); err != nil {
t.Fatalf("Bind failed: %v", err)
}
- err = c.EP.Listen(10)
- if err != nil {
+ if err := c.EP.Listen(10); err != nil {
t.Fatalf("Listen failed: %v", err)
}
c.EP.Close()
@@ -2671,8 +2890,7 @@ func TestReusePort(t *testing.T) {
if err := c.EP.Bind(tcpip.FullAddress{Port: context.StackPort}, nil); err != nil {
t.Fatalf("Bind failed: %v", err)
}
- err = c.EP.Listen(10)
- if err != nil {
+ if err := c.EP.Listen(10); err != nil {
t.Fatalf("Listen failed: %v", err)
}
}
@@ -2686,7 +2904,7 @@ func checkRecvBufferSize(t *testing.T, ep tcpip.Endpoint, v int) {
}
if int(s) != v {
- t.Fatalf("Bad receive buffer size: want=%v, got=%v", v, s)
+ t.Fatalf("got receive buffer size = %v, want = %v", s, v)
}
}
@@ -2699,7 +2917,7 @@ func checkSendBufferSize(t *testing.T, ep tcpip.Endpoint, v int) {
}
if int(s) != v {
- t.Fatalf("Bad send buffer size: want=%v, got=%v", v, s)
+ t.Fatalf("got send buffer size = %v, want = %v", s, v)
}
}
@@ -2840,14 +3058,12 @@ func TestSelfConnect(t *testing.T) {
wq.EventRegister(&waitEntry, waiter.EventOut)
defer wq.EventUnregister(&waitEntry)
- err = ep.Connect(tcpip.FullAddress{Addr: context.StackAddr, Port: context.StackPort})
- if err != tcpip.ErrConnectStarted {
- t.Fatalf("Unexpected return value from Connect: %v", err)
+ if err := ep.Connect(tcpip.FullAddress{Addr: context.StackAddr, Port: context.StackPort}); err != tcpip.ErrConnectStarted {
+ t.Fatalf("got ep.Connect(...) = %v, want = %v", err, tcpip.ErrConnectStarted)
}
<-notifyCh
- err = ep.GetSockOpt(tcpip.ErrorOption{})
- if err != nil {
+ if err := ep.GetSockOpt(tcpip.ErrorOption{}); err != nil {
t.Fatalf("Connect failed: %v", err)
}
@@ -2855,7 +3071,7 @@ func TestSelfConnect(t *testing.T) {
data := []byte{1, 2, 3}
view := buffer.NewView(len(data))
copy(view, data)
- if _, err = ep.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
+ if _, err := ep.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
t.Fatalf("Write failed: %v", err)
}
@@ -2874,8 +3090,8 @@ func TestSelfConnect(t *testing.T) {
}
}
- if bytes.Compare(data, rd) != 0 {
- t.Fatalf("Data is different: want=%v, got=%v", data, rd)
+ if !bytes.Equal(data, rd) {
+ t.Fatalf("got data = %v, want = %v", rd, data)
}
}
@@ -2949,16 +3165,16 @@ func TestTCPEndpointProbe(t *testing.T) {
// We don't do an extensive validation of every field but a
// basic sanity test.
if got, want := state.ID.LocalAddress, tcpip.Address(context.StackAddr); got != want {
- t.Fatalf("unexpected LocalAddress got: %q, want: %q", got, want)
+ t.Fatalf("got LocalAddress: %q, want: %q", got, want)
}
if got, want := state.ID.LocalPort, c.Port; got != want {
- t.Fatalf("unexpected LocalPort got: %d, want: %d", got, want)
+ t.Fatalf("got LocalPort: %d, want: %d", got, want)
}
if got, want := state.ID.RemoteAddress, tcpip.Address(context.TestAddr); got != want {
- t.Fatalf("unexpected RemoteAddress got: %q, want: %q", got, want)
+ t.Fatalf("got RemoteAddress: %q, want: %q", got, want)
}
if got, want := state.ID.RemotePort, uint16(context.TestPort); got != want {
- t.Fatalf("unexpected RemotePort got: %d, want: %d", got, want)
+ t.Fatalf("got RemotePort: %d, want: %d", got, want)
}
invoked <- struct{}{}
@@ -3008,7 +3224,7 @@ func TestSetCongestionControl(t *testing.T) {
t.Fatalf("s.TransportProtocolOption(%v, %v) = %v", tcp.ProtocolNumber, &cc, err)
}
if got, want := cc, tc.cc; got != want {
- t.Fatalf("unexpected value for congestion control got: %v, want: %v", got, want)
+ t.Fatalf("got congestion control: %v, want: %v", got, want)
}
})
}
@@ -3026,7 +3242,7 @@ func TestAvailableCongestionControl(t *testing.T) {
t.Fatalf("s.TransportProtocolOption(%v, %v) = %v", tcp.ProtocolNumber, &aCC, err)
}
if got, want := aCC, tcp.AvailableCongestionControlOption("reno cubic"); got != want {
- t.Fatalf("unexpected value for AvailableCongestionControlOption: got: %v, want: %v", got, want)
+ t.Fatalf("got tcp.AvailableCongestionControlOption: %v, want: %v", got, want)
}
}
@@ -3048,7 +3264,7 @@ func TestSetAvailableCongestionControl(t *testing.T) {
t.Fatalf("s.TransportProtocolOption(%v, %v) = %v", tcp.ProtocolNumber, &cc, err)
}
if got, want := cc, tcp.AvailableCongestionControlOption("reno cubic"); got != want {
- t.Fatalf("unexpected value for available congestion control got: %v, want: %v", got, want)
+ t.Fatalf("got tcp.AvailableCongestionControlOption: %v, want: %v", got, want)
}
}
diff --git a/pkg/tcpip/transport/tcp/tcp_timestamp_test.go b/pkg/tcpip/transport/tcp/tcp_timestamp_test.go
index a529d9e72..894ead507 100644
--- a/pkg/tcpip/transport/tcp/tcp_timestamp_test.go
+++ b/pkg/tcpip/transport/tcp/tcp_timestamp_test.go
@@ -267,8 +267,7 @@ func TestSegmentDropWhenTimestampMissing(t *testing.T) {
c.WQ.EventRegister(&we, waiter.EventIn)
defer c.WQ.EventUnregister(&we)
- stk := c.Stack()
- droppedPacketsStat := stk.Stats().DroppedPackets
+ droppedPacketsStat := c.Stack().Stats().DroppedPackets
droppedPackets := droppedPacketsStat.Value()
data := []byte{1, 2, 3}
// Save the sequence number as we will reset it later down
diff --git a/pkg/tcpip/transport/tcp/testing/context/context.go b/pkg/tcpip/transport/tcp/testing/context/context.go
index 6b5786140..c46af4b8b 100644
--- a/pkg/tcpip/transport/tcp/testing/context/context.go
+++ b/pkg/tcpip/transport/tcp/testing/context/context.go
@@ -295,9 +295,8 @@ func (c *Context) SendICMPPacket(typ header.ICMPv4Type, code uint8, p1, p2 []byt
c.linkEP.Inject(ipv4.ProtocolNumber, &vv)
}
-// SendPacket builds and sends a TCP segment(with the provided payload & TCP
-// headers) in an IPv4 packet via the link layer endpoint.
-func (c *Context) SendPacket(payload []byte, h *Headers) {
+// BuildSegment builds a TCP segment based on the given Headers and payload.
+func (c *Context) BuildSegment(payload []byte, h *Headers) buffer.VectorisedView {
// Allocate a buffer for data and headers.
buf := buffer.NewView(header.TCPMinimumSize + header.IPv4MinimumSize + len(h.TCPOpts) + len(payload))
copy(buf[len(buf)-len(payload):], payload)
@@ -340,6 +339,20 @@ func (c *Context) SendPacket(payload []byte, h *Headers) {
// Inject packet.
var views [1]buffer.View
vv := buf.ToVectorisedView(views)
+
+ return vv
+}
+
+// SendSegment sends a TCP segment that has already been built and written to a
+// buffer.VectorisedView.
+func (c *Context) SendSegment(s *buffer.VectorisedView) {
+ c.linkEP.Inject(ipv4.ProtocolNumber, s)
+}
+
+// SendPacket builds and sends a TCP segment(with the provided payload & TCP
+// headers) in an IPv4 packet via the link layer endpoint.
+func (c *Context) SendPacket(payload []byte, h *Headers) {
+ vv := c.BuildSegment(payload, h)
c.linkEP.Inject(ipv4.ProtocolNumber, &vv)
}