summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip
diff options
context:
space:
mode:
authorIan Gudger <igudger@google.com>2018-05-01 22:11:07 -0700
committerShentubot <shentubot@google.com>2018-05-01 22:11:49 -0700
commit3d3deef573a54e031cb98038b9f617f5fac31044 (patch)
tree9ed71c29dbabc80845a6b7e5510717cad354c309 /pkg/tcpip
parent185233427b3834086a9050336113f9e22176fa3b (diff)
Implement SO_TIMESTAMP
PiperOrigin-RevId: 195047018 Change-Id: I6d99528a00a2125f414e1e51e067205289ec9d3d
Diffstat (limited to 'pkg/tcpip')
-rw-r--r--pkg/tcpip/adapters/gonet/gonet.go4
-rw-r--r--pkg/tcpip/adapters/gonet/gonet_test.go2
-rw-r--r--pkg/tcpip/network/arp/arp_test.go2
-rw-r--r--pkg/tcpip/network/ipv4/icmp_test.go2
-rw-r--r--pkg/tcpip/sample/tun_tcp_connect/main.go4
-rw-r--r--pkg/tcpip/sample/tun_tcp_echo/main.go4
-rw-r--r--pkg/tcpip/stack/stack.go17
-rw-r--r--pkg/tcpip/stack/stack_test.go22
-rw-r--r--pkg/tcpip/stack/transport_test.go16
-rw-r--r--pkg/tcpip/tcpip.go48
-rw-r--r--pkg/tcpip/transport/tcp/endpoint.go22
-rw-r--r--pkg/tcpip/transport/tcp/tcp_test.go46
-rw-r--r--pkg/tcpip/transport/tcp/tcp_timestamp_test.go4
-rw-r--r--pkg/tcpip/transport/tcp/testing/context/context.go2
-rw-r--r--pkg/tcpip/transport/udp/endpoint.go37
-rw-r--r--pkg/tcpip/transport/udp/udp_test.go10
16 files changed, 162 insertions, 80 deletions
diff --git a/pkg/tcpip/adapters/gonet/gonet.go b/pkg/tcpip/adapters/gonet/gonet.go
index 96a2d670d..5aa6b1aa2 100644
--- a/pkg/tcpip/adapters/gonet/gonet.go
+++ b/pkg/tcpip/adapters/gonet/gonet.go
@@ -268,7 +268,7 @@ type opErrorer interface {
// commonRead implements the common logic between net.Conn.Read and
// net.PacketConn.ReadFrom.
func commonRead(ep tcpip.Endpoint, wq *waiter.Queue, deadline <-chan struct{}, addr *tcpip.FullAddress, errorer opErrorer) ([]byte, error) {
- read, err := ep.Read(addr)
+ read, _, err := ep.Read(addr)
if err == tcpip.ErrWouldBlock {
// Create wait queue entry that notifies a channel.
@@ -276,7 +276,7 @@ func commonRead(ep tcpip.Endpoint, wq *waiter.Queue, deadline <-chan struct{}, a
wq.EventRegister(&waitEntry, waiter.EventIn)
defer wq.EventUnregister(&waitEntry)
for {
- read, err = ep.Read(addr)
+ read, _, err = ep.Read(addr)
if err != tcpip.ErrWouldBlock {
break
}
diff --git a/pkg/tcpip/adapters/gonet/gonet_test.go b/pkg/tcpip/adapters/gonet/gonet_test.go
index 2f86469eb..e3d0c6c84 100644
--- a/pkg/tcpip/adapters/gonet/gonet_test.go
+++ b/pkg/tcpip/adapters/gonet/gonet_test.go
@@ -47,7 +47,7 @@ func TestTimeouts(t *testing.T) {
func newLoopbackStack() (*stack.Stack, *tcpip.Error) {
// Create the stack and add a NIC.
- s := stack.New([]string{ipv4.ProtocolName, ipv6.ProtocolName}, []string{tcp.ProtocolName, udp.ProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName, ipv6.ProtocolName}, []string{tcp.ProtocolName, udp.ProtocolName})
if err := s.CreateNIC(NICID, loopback.New()); err != nil {
return nil, err
diff --git a/pkg/tcpip/network/arp/arp_test.go b/pkg/tcpip/network/arp/arp_test.go
index 91ffdce4b..47b10e64e 100644
--- a/pkg/tcpip/network/arp/arp_test.go
+++ b/pkg/tcpip/network/arp/arp_test.go
@@ -32,7 +32,7 @@ type testContext struct {
}
func newTestContext(t *testing.T) *testContext {
- s := stack.New([]string{ipv4.ProtocolName, arp.ProtocolName}, []string{ipv4.PingProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName, arp.ProtocolName}, []string{ipv4.PingProtocolName})
const defaultMTU = 65536
id, linkEP := channel.New(256, defaultMTU, stackLinkAddr)
diff --git a/pkg/tcpip/network/ipv4/icmp_test.go b/pkg/tcpip/network/ipv4/icmp_test.go
index 378fba74b..c55aa1835 100644
--- a/pkg/tcpip/network/ipv4/icmp_test.go
+++ b/pkg/tcpip/network/ipv4/icmp_test.go
@@ -26,7 +26,7 @@ type testContext struct {
}
func newTestContext(t *testing.T) *testContext {
- s := stack.New([]string{ipv4.ProtocolName}, []string{ipv4.PingProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName}, []string{ipv4.PingProtocolName})
const defaultMTU = 65536
id, linkEP := channel.New(256, defaultMTU, "")
diff --git a/pkg/tcpip/sample/tun_tcp_connect/main.go b/pkg/tcpip/sample/tun_tcp_connect/main.go
index 332929c85..ef5c7ec60 100644
--- a/pkg/tcpip/sample/tun_tcp_connect/main.go
+++ b/pkg/tcpip/sample/tun_tcp_connect/main.go
@@ -113,7 +113,7 @@ func main() {
// Create the stack with ipv4 and tcp protocols, then add a tun-based
// NIC and ipv4 address.
- s := stack.New([]string{ipv4.ProtocolName}, []string{tcp.ProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName}, []string{tcp.ProtocolName})
mtu, err := rawfile.GetMTU(tunName)
if err != nil {
@@ -183,7 +183,7 @@ func main() {
// connection from its side.
wq.EventRegister(&waitEntry, waiter.EventIn)
for {
- v, err := ep.Read(nil)
+ v, _, err := ep.Read(nil)
if err != nil {
if err == tcpip.ErrClosedForReceive {
break
diff --git a/pkg/tcpip/sample/tun_tcp_echo/main.go b/pkg/tcpip/sample/tun_tcp_echo/main.go
index 10cd701af..8c166f643 100644
--- a/pkg/tcpip/sample/tun_tcp_echo/main.go
+++ b/pkg/tcpip/sample/tun_tcp_echo/main.go
@@ -42,7 +42,7 @@ func echo(wq *waiter.Queue, ep tcpip.Endpoint) {
defer wq.EventUnregister(&waitEntry)
for {
- v, err := ep.Read(nil)
+ v, _, err := ep.Read(nil)
if err != nil {
if err == tcpip.ErrWouldBlock {
<-notifyCh
@@ -99,7 +99,7 @@ func main() {
// Create the stack with ip and tcp protocols, then add a tun-based
// NIC and address.
- s := stack.New([]string{ipv4.ProtocolName, ipv6.ProtocolName, arp.ProtocolName}, []string{tcp.ProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName, ipv6.ProtocolName, arp.ProtocolName}, []string{tcp.ProtocolName})
mtu, err := rawfile.GetMTU(tunName)
if err != nil {
diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go
index 558ecdb72..b480bf812 100644
--- a/pkg/tcpip/stack/stack.go
+++ b/pkg/tcpip/stack/stack.go
@@ -270,6 +270,9 @@ type Stack struct {
// If not nil, then any new endpoints will have this probe function
// invoked everytime they receive a TCP segment.
tcpProbeFunc TCPProbeFunc
+
+ // clock is used to generate user-visible times.
+ clock tcpip.Clock
}
// New allocates a new networking stack with only the requested networking and
@@ -279,7 +282,7 @@ type Stack struct {
// SetNetworkProtocolOption/SetTransportProtocolOption methods provided by the
// stack. Please refer to individual protocol implementations as to what options
// are supported.
-func New(network []string, transport []string) *Stack {
+func New(clock tcpip.Clock, network []string, transport []string) *Stack {
s := &Stack{
transportProtocols: make(map[tcpip.TransportProtocolNumber]*transportProtocolState),
networkProtocols: make(map[tcpip.NetworkProtocolNumber]NetworkProtocol),
@@ -287,6 +290,7 @@ func New(network []string, transport []string) *Stack {
nics: make(map[tcpip.NICID]*NIC),
linkAddrCache: newLinkAddrCache(ageLimit, resolutionTimeout, resolutionAttempts),
PortManager: ports.NewPortManager(),
+ clock: clock,
}
// Add specified network protocols.
@@ -388,6 +392,11 @@ func (s *Stack) SetTransportProtocolHandler(p tcpip.TransportProtocolNumber, h f
}
}
+// NowNanoseconds implements tcpip.Clock.NowNanoseconds.
+func (s *Stack) NowNanoseconds() int64 {
+ return s.clock.NowNanoseconds()
+}
+
// Stats returns a snapshot of the current stats.
//
// NOTE: The underlying stats are updated using atomic instructions as a result
@@ -474,6 +483,12 @@ func (s *Stack) CreateDisabledNIC(id tcpip.NICID, linkEP tcpip.LinkEndpointID) *
return s.createNIC(id, "", linkEP, false)
}
+// CreateDisabledNamedNIC is a combination of CreateNamedNIC and
+// CreateDisabledNIC.
+func (s *Stack) CreateDisabledNamedNIC(id tcpip.NICID, name string, linkEP tcpip.LinkEndpointID) *tcpip.Error {
+ return s.createNIC(id, name, linkEP, false)
+}
+
// EnableNIC enables the given NIC so that the link-layer endpoint can start
// delivering packets to it.
func (s *Stack) EnableNIC(id tcpip.NICID) *tcpip.Error {
diff --git a/pkg/tcpip/stack/stack_test.go b/pkg/tcpip/stack/stack_test.go
index b416065d7..ea7dccdc2 100644
--- a/pkg/tcpip/stack/stack_test.go
+++ b/pkg/tcpip/stack/stack_test.go
@@ -176,7 +176,7 @@ func TestNetworkReceive(t *testing.T) {
// Create a stack with the fake network protocol, one nic, and two
// addresses attached to it: 1 & 2.
id, linkEP := channel.New(10, defaultMTU, "")
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
if err := s.CreateNIC(1, id); err != nil {
t.Fatalf("CreateNIC failed: %v", err)
}
@@ -270,7 +270,7 @@ func TestNetworkSend(t *testing.T) {
// address: 1. The route table sends all packets through the only
// existing nic.
id, linkEP := channel.New(10, defaultMTU, "")
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
if err := s.CreateNIC(1, id); err != nil {
t.Fatalf("NewNIC failed: %v", err)
}
@@ -292,7 +292,7 @@ func TestNetworkSendMultiRoute(t *testing.T) {
// Create a stack with the fake network protocol, two nics, and two
// addresses per nic, the first nic has odd address, the second one has
// even addresses.
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
id1, linkEP1 := channel.New(10, defaultMTU, "")
if err := s.CreateNIC(1, id1); err != nil {
@@ -371,7 +371,7 @@ func TestRoutes(t *testing.T) {
// Create a stack with the fake network protocol, two nics, and two
// addresses per nic, the first nic has odd address, the second one has
// even addresses.
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
id1, _ := channel.New(10, defaultMTU, "")
if err := s.CreateNIC(1, id1); err != nil {
@@ -435,7 +435,7 @@ func TestRoutes(t *testing.T) {
}
func TestAddressRemoval(t *testing.T) {
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
id, linkEP := channel.New(10, defaultMTU, "")
if err := s.CreateNIC(1, id); err != nil {
@@ -479,7 +479,7 @@ func TestAddressRemoval(t *testing.T) {
}
func TestDelayedRemovalDueToRoute(t *testing.T) {
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
id, linkEP := channel.New(10, defaultMTU, "")
if err := s.CreateNIC(1, id); err != nil {
@@ -547,7 +547,7 @@ func TestDelayedRemovalDueToRoute(t *testing.T) {
}
func TestPromiscuousMode(t *testing.T) {
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
id, linkEP := channel.New(10, defaultMTU, "")
if err := s.CreateNIC(1, id); err != nil {
@@ -607,7 +607,7 @@ func TestAddressSpoofing(t *testing.T) {
srcAddr := tcpip.Address("\x01")
dstAddr := tcpip.Address("\x02")
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
id, _ := channel.New(10, defaultMTU, "")
if err := s.CreateNIC(1, id); err != nil {
@@ -648,7 +648,7 @@ func TestAddressSpoofing(t *testing.T) {
// Set the subnet, then check that packet is delivered.
func TestSubnetAcceptsMatchingPacket(t *testing.T) {
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
id, linkEP := channel.New(10, defaultMTU, "")
if err := s.CreateNIC(1, id); err != nil {
@@ -682,7 +682,7 @@ func TestSubnetAcceptsMatchingPacket(t *testing.T) {
// Set destination outside the subnet, then check it doesn't get delivered.
func TestSubnetRejectsNonmatchingPacket(t *testing.T) {
- s := stack.New([]string{"fakeNet"}, nil)
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, nil)
id, linkEP := channel.New(10, defaultMTU, "")
if err := s.CreateNIC(1, id); err != nil {
@@ -714,7 +714,7 @@ func TestSubnetRejectsNonmatchingPacket(t *testing.T) {
}
func TestNetworkOptions(t *testing.T) {
- s := stack.New([]string{"fakeNet"}, []string{})
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, []string{})
// Try an unsupported network protocol.
if err := s.SetNetworkProtocolOption(tcpip.NetworkProtocolNumber(99999), fakeNetGoodOption(false)); err != tcpip.ErrUnknownProtocol {
diff --git a/pkg/tcpip/stack/transport_test.go b/pkg/tcpip/stack/transport_test.go
index 7e072e96e..b870ab375 100644
--- a/pkg/tcpip/stack/transport_test.go
+++ b/pkg/tcpip/stack/transport_test.go
@@ -46,8 +46,8 @@ func (*fakeTransportEndpoint) Readiness(mask waiter.EventMask) waiter.EventMask
return mask
}
-func (*fakeTransportEndpoint) Read(*tcpip.FullAddress) (buffer.View, *tcpip.Error) {
- return buffer.View{}, nil
+func (*fakeTransportEndpoint) Read(*tcpip.FullAddress) (buffer.View, tcpip.ControlMessages, *tcpip.Error) {
+ return buffer.View{}, tcpip.ControlMessages{}, nil
}
func (f *fakeTransportEndpoint) Write(p tcpip.Payload, opts tcpip.WriteOptions) (uintptr, *tcpip.Error) {
@@ -67,8 +67,8 @@ func (f *fakeTransportEndpoint) Write(p tcpip.Payload, opts tcpip.WriteOptions)
return uintptr(len(v)), nil
}
-func (f *fakeTransportEndpoint) Peek([][]byte) (uintptr, *tcpip.Error) {
- return 0, nil
+func (f *fakeTransportEndpoint) Peek([][]byte) (uintptr, tcpip.ControlMessages, *tcpip.Error) {
+ return 0, tcpip.ControlMessages{}, nil
}
// SetSockOpt sets a socket option. Currently not supported.
@@ -210,7 +210,7 @@ func (f *fakeTransportProtocol) Option(option interface{}) *tcpip.Error {
func TestTransportReceive(t *testing.T) {
id, linkEP := channel.New(10, defaultMTU, "")
- s := stack.New([]string{"fakeNet"}, []string{"fakeTrans"})
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, []string{"fakeTrans"})
if err := s.CreateNIC(1, id); err != nil {
t.Fatalf("CreateNIC failed: %v", err)
}
@@ -270,7 +270,7 @@ func TestTransportReceive(t *testing.T) {
func TestTransportControlReceive(t *testing.T) {
id, linkEP := channel.New(10, defaultMTU, "")
- s := stack.New([]string{"fakeNet"}, []string{"fakeTrans"})
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, []string{"fakeTrans"})
if err := s.CreateNIC(1, id); err != nil {
t.Fatalf("CreateNIC failed: %v", err)
}
@@ -336,7 +336,7 @@ func TestTransportControlReceive(t *testing.T) {
func TestTransportSend(t *testing.T) {
id, _ := channel.New(10, defaultMTU, "")
- s := stack.New([]string{"fakeNet"}, []string{"fakeTrans"})
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, []string{"fakeTrans"})
if err := s.CreateNIC(1, id); err != nil {
t.Fatalf("CreateNIC failed: %v", err)
}
@@ -373,7 +373,7 @@ func TestTransportSend(t *testing.T) {
}
func TestTransportOptions(t *testing.T) {
- s := stack.New([]string{"fakeNet"}, []string{"fakeTrans"})
+ s := stack.New(&tcpip.StdClock{}, []string{"fakeNet"}, []string{"fakeTrans"})
// Try an unsupported transport protocol.
if err := s.SetTransportProtocolOption(tcpip.TransportProtocolNumber(99999), fakeTransportGoodOption(false)); err != tcpip.ErrUnknownProtocol {
diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go
index f3a94f353..f9df1d989 100644
--- a/pkg/tcpip/tcpip.go
+++ b/pkg/tcpip/tcpip.go
@@ -23,6 +23,7 @@ import (
"fmt"
"strconv"
"strings"
+ "time"
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
"gvisor.googlesource.com/gvisor/pkg/waiter"
@@ -80,6 +81,24 @@ var (
errSubnetAddressMasked = errors.New("subnet address has bits set outside the mask")
)
+// A Clock provides the current time.
+//
+// Times returned by a Clock should always be used for application-visible
+// time, but never for netstack internal timekeeping.
+type Clock interface {
+ // NowNanoseconds returns the current real time as a number of
+ // nanoseconds since some epoch.
+ NowNanoseconds() int64
+}
+
+// StdClock implements Clock with the time package.
+type StdClock struct{}
+
+// NowNanoseconds implements Clock.NowNanoseconds.
+func (*StdClock) NowNanoseconds() int64 {
+ return time.Now().UnixNano()
+}
+
// Address is a byte slice cast as a string that represents the address of a
// network node. Or, in the case of unix endpoints, it may represent a path.
type Address string
@@ -210,6 +229,16 @@ func (s SlicePayload) Size() int {
return len(s)
}
+// A ControlMessages contains socket control messages for IP sockets.
+type ControlMessages struct {
+ // HasTimestamp indicates whether Timestamp is valid/set.
+ HasTimestamp bool
+
+ // Timestamp is the time (in ns) that the last packed used to create
+ // the read data was received.
+ Timestamp int64
+}
+
// Endpoint is the interface implemented by transport protocols (e.g., tcp, udp)
// that exposes functionality like read, write, connect, etc. to users of the
// networking stack.
@@ -219,9 +248,13 @@ type Endpoint interface {
Close()
// Read reads data from the endpoint and optionally returns the sender.
- // This method does not block if there is no data pending.
- // It will also either return an error or data, never both.
- Read(*FullAddress) (buffer.View, *Error)
+ //
+ // This method does not block if there is no data pending. It will also
+ // either return an error or data, never both.
+ //
+ // A timestamp (in ns) is optionally returned. A zero value indicates
+ // that no timestamp was available.
+ Read(*FullAddress) (buffer.View, ControlMessages, *Error)
// Write writes data to the endpoint's peer. This method does not block if
// the data cannot be written.
@@ -238,7 +271,10 @@ type Endpoint interface {
// Peek reads data without consuming it from the endpoint.
//
// This method does not block if there is no data pending.
- Peek([][]byte) (uintptr, *Error)
+ //
+ // A timestamp (in ns) is optionally returned. A zero value indicates
+ // that no timestamp was available.
+ Peek([][]byte) (uintptr, ControlMessages, *Error)
// Connect connects the endpoint to its peer. Specifying a NIC is
// optional.
@@ -347,6 +383,10 @@ type ReuseAddressOption int
// Only supported on Unix sockets.
type PasscredOption int
+// TimestampOption is used by SetSockOpt/GetSockOpt to specify whether
+// SO_TIMESTAMP socket control messages are enabled.
+type TimestampOption int
+
// TCPInfoOption is used by GetSockOpt to expose TCP statistics.
//
// TODO: Add and populate stat fields.
diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go
index 5d62589d8..d84171b0c 100644
--- a/pkg/tcpip/transport/tcp/endpoint.go
+++ b/pkg/tcpip/transport/tcp/endpoint.go
@@ -374,7 +374,7 @@ func (e *endpoint) cleanup() {
}
// Read reads data from the endpoint.
-func (e *endpoint) Read(*tcpip.FullAddress) (buffer.View, *tcpip.Error) {
+func (e *endpoint) Read(*tcpip.FullAddress) (buffer.View, tcpip.ControlMessages, *tcpip.Error) {
e.mu.RLock()
// The endpoint can be read if it's connected, or if it's already closed
// but has some pending unread data. Also note that a RST being received
@@ -383,9 +383,9 @@ func (e *endpoint) Read(*tcpip.FullAddress) (buffer.View, *tcpip.Error) {
if s := e.state; s != stateConnected && s != stateClosed && e.rcvBufUsed == 0 {
e.mu.RUnlock()
if s == stateError {
- return buffer.View{}, e.hardError
+ return buffer.View{}, tcpip.ControlMessages{}, e.hardError
}
- return buffer.View{}, tcpip.ErrInvalidEndpointState
+ return buffer.View{}, tcpip.ControlMessages{}, tcpip.ErrInvalidEndpointState
}
e.rcvListMu.Lock()
@@ -394,7 +394,7 @@ func (e *endpoint) Read(*tcpip.FullAddress) (buffer.View, *tcpip.Error) {
e.mu.RUnlock()
- return v, err
+ return v, tcpip.ControlMessages{}, err
}
func (e *endpoint) readLocked() (buffer.View, *tcpip.Error) {
@@ -498,7 +498,7 @@ func (e *endpoint) Write(p tcpip.Payload, opts tcpip.WriteOptions) (uintptr, *tc
// Peek reads data without consuming it from the endpoint.
//
// This method does not block if there is no data pending.
-func (e *endpoint) Peek(vec [][]byte) (uintptr, *tcpip.Error) {
+func (e *endpoint) Peek(vec [][]byte) (uintptr, tcpip.ControlMessages, *tcpip.Error) {
e.mu.RLock()
defer e.mu.RUnlock()
@@ -506,9 +506,9 @@ func (e *endpoint) Peek(vec [][]byte) (uintptr, *tcpip.Error) {
// but has some pending unread data.
if s := e.state; s != stateConnected && s != stateClosed {
if s == stateError {
- return 0, e.hardError
+ return 0, tcpip.ControlMessages{}, e.hardError
}
- return 0, tcpip.ErrInvalidEndpointState
+ return 0, tcpip.ControlMessages{}, tcpip.ErrInvalidEndpointState
}
e.rcvListMu.Lock()
@@ -516,9 +516,9 @@ func (e *endpoint) Peek(vec [][]byte) (uintptr, *tcpip.Error) {
if e.rcvBufUsed == 0 {
if e.rcvClosed || e.state != stateConnected {
- return 0, tcpip.ErrClosedForReceive
+ return 0, tcpip.ControlMessages{}, tcpip.ErrClosedForReceive
}
- return 0, tcpip.ErrWouldBlock
+ return 0, tcpip.ControlMessages{}, tcpip.ErrWouldBlock
}
// Make a copy of vec so we can modify the slide headers.
@@ -534,7 +534,7 @@ func (e *endpoint) Peek(vec [][]byte) (uintptr, *tcpip.Error) {
for len(v) > 0 {
if len(vec) == 0 {
- return num, nil
+ return num, tcpip.ControlMessages{}, nil
}
if len(vec[0]) == 0 {
vec = vec[1:]
@@ -549,7 +549,7 @@ func (e *endpoint) Peek(vec [][]byte) (uintptr, *tcpip.Error) {
}
}
- return num, nil
+ return num, tcpip.ControlMessages{}, nil
}
// zeroReceiveWindow checks if the receive window to be announced now would be
diff --git a/pkg/tcpip/transport/tcp/tcp_test.go b/pkg/tcpip/transport/tcp/tcp_test.go
index 118d861ba..3c21a1ec3 100644
--- a/pkg/tcpip/transport/tcp/tcp_test.go
+++ b/pkg/tcpip/transport/tcp/tcp_test.go
@@ -147,7 +147,7 @@ func TestSimpleReceive(t *testing.T) {
c.WQ.EventRegister(&we, waiter.EventIn)
defer c.WQ.EventUnregister(&we)
- if _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
+ if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -169,7 +169,7 @@ func TestSimpleReceive(t *testing.T) {
}
// Receive data.
- v, err := c.EP.Read(nil)
+ v, _, err := c.EP.Read(nil)
if err != nil {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -199,7 +199,7 @@ func TestOutOfOrderReceive(t *testing.T) {
c.WQ.EventRegister(&we, waiter.EventIn)
defer c.WQ.EventUnregister(&we)
- if _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
+ if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -226,7 +226,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 {
+ if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -243,7 +243,7 @@ func TestOutOfOrderReceive(t *testing.T) {
// Receive data.
read := make([]byte, 0, 6)
for len(read) < len(data) {
- v, err := c.EP.Read(nil)
+ v, _, err := c.EP.Read(nil)
if err != nil {
if err == tcpip.ErrWouldBlock {
// Wait for receive to be notified.
@@ -284,7 +284,7 @@ func TestOutOfOrderFlood(t *testing.T) {
opt := tcpip.ReceiveBufferSizeOption(10)
c.CreateConnected(789, 30000, &opt)
- if _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
+ if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -361,7 +361,7 @@ func TestRstOnCloseWithUnreadData(t *testing.T) {
c.WQ.EventRegister(&we, waiter.EventIn)
defer c.WQ.EventUnregister(&we)
- if _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
+ if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -414,7 +414,7 @@ func TestFullWindowReceive(t *testing.T) {
c.WQ.EventRegister(&we, waiter.EventIn)
defer c.WQ.EventUnregister(&we)
- _, err := c.EP.Read(nil)
+ _, _, err := c.EP.Read(nil)
if err != tcpip.ErrWouldBlock {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -449,7 +449,7 @@ func TestFullWindowReceive(t *testing.T) {
)
// Receive data and check it.
- v, err := c.EP.Read(nil)
+ v, _, err := c.EP.Read(nil)
if err != nil {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -487,7 +487,7 @@ func TestNoWindowShrinking(t *testing.T) {
c.WQ.EventRegister(&we, waiter.EventIn)
defer c.WQ.EventUnregister(&we)
- _, err := c.EP.Read(nil)
+ _, _, err := c.EP.Read(nil)
if err != tcpip.ErrWouldBlock {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -551,7 +551,7 @@ func TestNoWindowShrinking(t *testing.T) {
// Receive data and check it.
read := make([]byte, 0, 10)
for len(read) < len(data) {
- v, err := c.EP.Read(nil)
+ v, _, err := c.EP.Read(nil)
if err != nil {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -954,7 +954,7 @@ func TestZeroScaledWindowReceive(t *testing.T) {
}
// Read some data. An ack should be sent in response to that.
- v, err := c.EP.Read(nil)
+ v, _, err := c.EP.Read(nil)
if err != nil {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -1337,7 +1337,7 @@ func TestReceiveOnResetConnection(t *testing.T) {
loop:
for {
- switch _, err := c.EP.Read(nil); err {
+ switch _, _, err := c.EP.Read(nil); err {
case nil:
t.Fatalf("Unexpected success.")
case tcpip.ErrWouldBlock:
@@ -2293,7 +2293,7 @@ func TestReadAfterClosedState(t *testing.T) {
c.WQ.EventRegister(&we, waiter.EventIn)
defer c.WQ.EventUnregister(&we)
- if _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
+ if _, _, err := c.EP.Read(nil); err != tcpip.ErrWouldBlock {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -2345,7 +2345,7 @@ func TestReadAfterClosedState(t *testing.T) {
// Check that peek works.
peekBuf := make([]byte, 10)
- n, err := c.EP.Peek([][]byte{peekBuf})
+ n, _, err := c.EP.Peek([][]byte{peekBuf})
if err != nil {
t.Fatalf("Unexpected error from Peek: %v", err)
}
@@ -2356,7 +2356,7 @@ func TestReadAfterClosedState(t *testing.T) {
}
// Receive data.
- v, err := c.EP.Read(nil)
+ v, _, err := c.EP.Read(nil)
if err != nil {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -2367,11 +2367,11 @@ func TestReadAfterClosedState(t *testing.T) {
// Now that we drained the queue, check that functions fail with the
// right error code.
- if _, err := c.EP.Read(nil); err != tcpip.ErrClosedForReceive {
+ if _, _, err := c.EP.Read(nil); err != tcpip.ErrClosedForReceive {
t.Fatalf("Unexpected return from Read: got %v, want %v", err, tcpip.ErrClosedForReceive)
}
- if _, err := c.EP.Peek([][]byte{peekBuf}); 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)
}
}
@@ -2479,7 +2479,7 @@ func checkSendBufferSize(t *testing.T, ep tcpip.Endpoint, v int) {
}
func TestDefaultBufferSizes(t *testing.T) {
- s := stack.New([]string{ipv4.ProtocolName}, []string{tcp.ProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName}, []string{tcp.ProtocolName})
// Check the default values.
ep, err := s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &waiter.Queue{})
@@ -2525,7 +2525,7 @@ func TestDefaultBufferSizes(t *testing.T) {
}
func TestMinMaxBufferSizes(t *testing.T) {
- s := stack.New([]string{ipv4.ProtocolName}, []string{tcp.ProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName}, []string{tcp.ProtocolName})
// Check the default values.
ep, err := s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &waiter.Queue{})
@@ -2575,7 +2575,7 @@ func TestSelfConnect(t *testing.T) {
// it checks that if an endpoint binds to say 127.0.0.1:1000 then
// connects to 127.0.0.1:1000, then it will be connected to itself, and
// is able to send and receive data through the same endpoint.
- s := stack.New([]string{ipv4.ProtocolName}, []string{tcp.ProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName}, []string{tcp.ProtocolName})
id := loopback.New()
if testing.Verbose() {
@@ -2637,13 +2637,13 @@ func TestSelfConnect(t *testing.T) {
// Read back what was written.
wq.EventUnregister(&waitEntry)
wq.EventRegister(&waitEntry, waiter.EventIn)
- rd, err := ep.Read(nil)
+ rd, _, err := ep.Read(nil)
if err != nil {
if err != tcpip.ErrWouldBlock {
t.Fatalf("Read failed: %v", err)
}
<-notifyCh
- rd, err = ep.Read(nil)
+ rd, _, err = ep.Read(nil)
if err != nil {
t.Fatalf("Read failed: %v", err)
}
diff --git a/pkg/tcpip/transport/tcp/tcp_timestamp_test.go b/pkg/tcpip/transport/tcp/tcp_timestamp_test.go
index d12081bb7..335262e43 100644
--- a/pkg/tcpip/transport/tcp/tcp_timestamp_test.go
+++ b/pkg/tcpip/transport/tcp/tcp_timestamp_test.go
@@ -95,7 +95,7 @@ func TestTimeStampEnabledConnect(t *testing.T) {
// There should be 5 views to read and each of them should
// contain the same data.
for i := 0; i < 5; i++ {
- got, err := c.EP.Read(nil)
+ got, _, err := c.EP.Read(nil)
if err != nil {
t.Fatalf("Unexpected error from Read: %v", err)
}
@@ -296,7 +296,7 @@ func TestSegmentDropWhenTimestampMissing(t *testing.T) {
}
// Issue a read and we should data.
- got, err := c.EP.Read(nil)
+ got, _, err := c.EP.Read(nil)
if err != nil {
t.Fatalf("Unexpected error from Read: %v", err)
}
diff --git a/pkg/tcpip/transport/tcp/testing/context/context.go b/pkg/tcpip/transport/tcp/testing/context/context.go
index 6a402d150..eb928553f 100644
--- a/pkg/tcpip/transport/tcp/testing/context/context.go
+++ b/pkg/tcpip/transport/tcp/testing/context/context.go
@@ -129,7 +129,7 @@ type Context struct {
// New allocates and initializes a test context containing a new
// stack and a link-layer endpoint.
func New(t *testing.T, mtu uint32) *Context {
- s := stack.New([]string{ipv4.ProtocolName, ipv6.ProtocolName}, []string{tcp.ProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName, ipv6.ProtocolName}, []string{tcp.ProtocolName})
// Allow minimum send/receive buffer sizes to be 1 during tests.
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SendBufferSizeOption{1, tcp.DefaultBufferSize, tcp.DefaultBufferSize * 10}); err != nil {
diff --git a/pkg/tcpip/transport/udp/endpoint.go b/pkg/tcpip/transport/udp/endpoint.go
index 80fa88c4c..f86fc6d5a 100644
--- a/pkg/tcpip/transport/udp/endpoint.go
+++ b/pkg/tcpip/transport/udp/endpoint.go
@@ -19,6 +19,8 @@ type udpPacket struct {
udpPacketEntry
senderAddress tcpip.FullAddress
data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
+ timestamp int64
+ hasTimestamp bool
// views is used as buffer for data when its length is large
// enough to store a VectorisedView.
views [8]buffer.View `state:"nosave"`
@@ -52,6 +54,7 @@ type endpoint struct {
rcvBufSizeMax int `state:".(int)"`
rcvBufSize int
rcvClosed bool
+ rcvTimestamp bool
// The following fields are protected by the mu mutex.
mu sync.RWMutex `state:"nosave"`
@@ -134,7 +137,7 @@ func (e *endpoint) Close() {
// Read reads data from the endpoint. This method does not block if
// there is no data pending.
-func (e *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, *tcpip.Error) {
+func (e *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, tcpip.ControlMessages, *tcpip.Error) {
e.rcvMu.Lock()
if e.rcvList.Empty() {
@@ -143,12 +146,13 @@ func (e *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, *tcpip.Error) {
err = tcpip.ErrClosedForReceive
}
e.rcvMu.Unlock()
- return buffer.View{}, err
+ return buffer.View{}, tcpip.ControlMessages{}, err
}
p := e.rcvList.Front()
e.rcvList.Remove(p)
e.rcvBufSize -= p.data.Size()
+ ts := e.rcvTimestamp
e.rcvMu.Unlock()
@@ -156,7 +160,12 @@ func (e *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, *tcpip.Error) {
*addr = p.senderAddress
}
- return p.data.ToView(), nil
+ if ts && !p.hasTimestamp {
+ // Linux uses the current time.
+ p.timestamp = e.stack.NowNanoseconds()
+ }
+
+ return p.data.ToView(), tcpip.ControlMessages{HasTimestamp: ts, Timestamp: p.timestamp}, nil
}
// prepareForWrite prepares the endpoint for sending data. In particular, it
@@ -299,8 +308,8 @@ func (e *endpoint) Write(p tcpip.Payload, opts tcpip.WriteOptions) (uintptr, *tc
}
// Peek only returns data from a single datagram, so do nothing here.
-func (e *endpoint) Peek([][]byte) (uintptr, *tcpip.Error) {
- return 0, nil
+func (e *endpoint) Peek([][]byte) (uintptr, tcpip.ControlMessages, *tcpip.Error) {
+ return 0, tcpip.ControlMessages{}, nil
}
// SetSockOpt sets a socket option. Currently not supported.
@@ -322,6 +331,11 @@ func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error {
}
e.v6only = v != 0
+
+ case tcpip.TimestampOption:
+ e.rcvMu.Lock()
+ e.rcvTimestamp = v != 0
+ e.rcvMu.Unlock()
}
return nil
}
@@ -370,6 +384,14 @@ func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error {
}
e.rcvMu.Unlock()
return nil
+
+ case *tcpip.TimestampOption:
+ e.rcvMu.Lock()
+ *o = 0
+ if e.rcvTimestamp {
+ *o = 1
+ }
+ e.rcvMu.Unlock()
}
return tcpip.ErrUnknownProtocolOption
@@ -733,6 +755,11 @@ func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv
e.rcvList.PushBack(pkt)
e.rcvBufSize += vv.Size()
+ if e.rcvTimestamp {
+ pkt.timestamp = e.stack.NowNanoseconds()
+ pkt.hasTimestamp = true
+ }
+
e.rcvMu.Unlock()
// Notify any waiters that there's data to be read now.
diff --git a/pkg/tcpip/transport/udp/udp_test.go b/pkg/tcpip/transport/udp/udp_test.go
index 65c567952..1eb9ecb80 100644
--- a/pkg/tcpip/transport/udp/udp_test.go
+++ b/pkg/tcpip/transport/udp/udp_test.go
@@ -56,7 +56,7 @@ type headers struct {
}
func newDualTestContext(t *testing.T, mtu uint32) *testContext {
- s := stack.New([]string{ipv4.ProtocolName, ipv6.ProtocolName}, []string{udp.ProtocolName})
+ s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName, ipv6.ProtocolName}, []string{udp.ProtocolName})
id, linkEP := channel.New(256, mtu, "")
if testing.Verbose() {
@@ -260,12 +260,12 @@ func testV4Read(c *testContext) {
defer c.wq.EventUnregister(&we)
var addr tcpip.FullAddress
- v, err := c.ep.Read(&addr)
+ v, _, err := c.ep.Read(&addr)
if err == tcpip.ErrWouldBlock {
// Wait for data to become available.
select {
case <-ch:
- v, err = c.ep.Read(&addr)
+ v, _, err = c.ep.Read(&addr)
if err != nil {
c.t.Fatalf("Read failed: %v", err)
}
@@ -355,12 +355,12 @@ func TestV6ReadOnV6(t *testing.T) {
defer c.wq.EventUnregister(&we)
var addr tcpip.FullAddress
- v, err := c.ep.Read(&addr)
+ v, _, err := c.ep.Read(&addr)
if err == tcpip.ErrWouldBlock {
// Wait for data to become available.
select {
case <-ch:
- v, err = c.ep.Read(&addr)
+ v, _, err = c.ep.Read(&addr)
if err != nil {
c.t.Fatalf("Read failed: %v", err)
}