summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/transport/udp
diff options
context:
space:
mode:
authorGhanan Gowripalan <ghanan@google.com>2021-01-13 16:02:26 -0800
committergVisor bot <gvisor-bot@google.com>2021-01-13 16:04:33 -0800
commit25b5ec7135a6de80674ac1ad4d2289c29e156f42 (patch)
tree5939fd3fd2e4afb2de9c4062cfd9066c544ab46e /pkg/tcpip/transport/udp
parent1efe0ebc5973ec8a06b881c087dae2183898504b (diff)
Do not resolve remote link address at transport layer
Link address resolution is performed at the link layer (if required) so we can defer it from the transport layer. When link resolution is required, packets will be queued and sent once link resolution completes. If link resolution fails, the transport layer will receive a control message indicating that the stack failed to route the packet. tcpip.Endpoint.Write no longer returns a channel now that writes do not wait for link resolution at the transport layer. tcpip.ErrNoLinkAddress is no longer used so it is removed. Removed calls to stack.Route.ResolveWith from the transport layer so that link resolution is performed when a route is created in response to an incoming packet (e.g. to complete TCP handshakes or send a RST). Tests: - integration_test.TestForwarding - integration_test.TestTCPLinkResolutionFailure Fixes #4458 RELNOTES: n/a PiperOrigin-RevId: 351684158
Diffstat (limited to 'pkg/tcpip/transport/udp')
-rw-r--r--pkg/tcpip/transport/udp/endpoint.go45
-rw-r--r--pkg/tcpip/transport/udp/forwarder.go1
-rw-r--r--pkg/tcpip/transport/udp/udp_test.go20
3 files changed, 26 insertions, 40 deletions
diff --git a/pkg/tcpip/transport/udp/endpoint.go b/pkg/tcpip/transport/udp/endpoint.go
index 5d87f3a7e..520a0ac9d 100644
--- a/pkg/tcpip/transport/udp/endpoint.go
+++ b/pkg/tcpip/transport/udp/endpoint.go
@@ -417,8 +417,8 @@ func (e *endpoint) connectRoute(nicID tcpip.NICID, addr tcpip.FullAddress, netPr
// Write writes data to the endpoint's peer. This method does not block
// if the data cannot be written.
-func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-chan struct{}, *tcpip.Error) {
- n, ch, err := e.write(p, opts)
+func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, *tcpip.Error) {
+ n, err := e.write(p, opts)
switch err {
case nil:
e.stats.PacketsSent.Increment()
@@ -428,8 +428,6 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
e.stats.WriteErrors.WriteClosed.Increment()
case tcpip.ErrInvalidEndpointState:
e.stats.WriteErrors.InvalidEndpointState.Increment()
- case tcpip.ErrNoLinkAddress:
- e.stats.SendErrors.NoLinkAddr.Increment()
case tcpip.ErrNoRoute, tcpip.ErrBroadcastDisabled, tcpip.ErrNetworkUnreachable:
// Errors indicating any problem with IP routing of the packet.
e.stats.SendErrors.NoRoute.Increment()
@@ -437,17 +435,17 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
// For all other errors when writing to the network layer.
e.stats.SendErrors.SendToNetworkFailed.Increment()
}
- return n, ch, err
+ return n, err
}
-func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-chan struct{}, *tcpip.Error) {
+func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, *tcpip.Error) {
if err := e.LastError(); err != nil {
- return 0, nil, err
+ return 0, err
}
// MSG_MORE is unimplemented. (This also means that MSG_EOR is a no-op.)
if opts.More {
- return 0, nil, tcpip.ErrInvalidOptionValue
+ return 0, tcpip.ErrInvalidOptionValue
}
to := opts.To
@@ -463,14 +461,14 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
// If we've shutdown with SHUT_WR we are in an invalid state for sending.
if e.shutdownFlags&tcpip.ShutdownWrite != 0 {
- return 0, nil, tcpip.ErrClosedForSend
+ return 0, tcpip.ErrClosedForSend
}
// Prepare for write.
for {
retry, err := e.prepareForWrite(to)
if err != nil {
- return 0, nil, err
+ return 0, err
}
if !retry {
@@ -486,7 +484,7 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
nicID := to.NIC
if e.BindNICID != 0 {
if nicID != 0 && nicID != e.BindNICID {
- return 0, nil, tcpip.ErrNoRoute
+ return 0, tcpip.ErrNoRoute
}
nicID = e.BindNICID
@@ -494,17 +492,17 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
if to.Port == 0 {
// Port 0 is an invalid port to send to.
- return 0, nil, tcpip.ErrInvalidEndpointState
+ return 0, tcpip.ErrInvalidEndpointState
}
dst, netProto, err := e.checkV4MappedLocked(*to)
if err != nil {
- return 0, nil, err
+ return 0, err
}
r, _, err := e.connectRoute(nicID, dst, netProto)
if err != nil {
- return 0, nil, err
+ return 0, err
}
defer r.Release()
@@ -513,21 +511,12 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
}
if !e.ops.GetBroadcast() && route.IsOutboundBroadcast() {
- return 0, nil, tcpip.ErrBroadcastDisabled
- }
-
- if route.IsResolutionRequired() {
- if ch, err := route.Resolve(nil); err != nil {
- if err == tcpip.ErrWouldBlock {
- return 0, ch, tcpip.ErrNoLinkAddress
- }
- return 0, nil, err
- }
+ return 0, tcpip.ErrBroadcastDisabled
}
v, err := p.FullPayload()
if err != nil {
- return 0, nil, err
+ return 0, err
}
if len(v) > header.UDPMaximumPacketSize {
// Payload can't possibly fit in a packet.
@@ -545,7 +534,7 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
v,
)
}
- return 0, nil, tcpip.ErrMessageTooLong
+ return 0, tcpip.ErrMessageTooLong
}
ttl := e.ttl
@@ -575,9 +564,9 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
// See: https://golang.org/pkg/sync/#RWMutex for details on why recursive read
// locking is prohibited.
if err := sendUDP(route, buffer.View(v).ToVectorisedView(), localPort, dstPort, ttl, useDefaultTTL, sendTOS, owner, noChecksum); err != nil {
- return 0, nil, err
+ return 0, err
}
- return int64(len(v)), nil, nil
+ return int64(len(v)), nil
}
// OnReuseAddressSet implements tcpip.SocketOptionsHandler.OnReuseAddressSet.
diff --git a/pkg/tcpip/transport/udp/forwarder.go b/pkg/tcpip/transport/udp/forwarder.go
index d7fc21f11..49e673d58 100644
--- a/pkg/tcpip/transport/udp/forwarder.go
+++ b/pkg/tcpip/transport/udp/forwarder.go
@@ -75,7 +75,6 @@ func (r *ForwarderRequest) CreateEndpoint(queue *waiter.Queue) (tcpip.Endpoint,
if err != nil {
return nil, err
}
- route.ResolveWith(r.pkt.SourceLinkAddress())
ep := newEndpoint(r.stack, r.pkt.NetworkProtocolNumber, queue)
if err := r.stack.RegisterTransportEndpoint(r.pkt.NICID, []tcpip.NetworkProtocolNumber{r.pkt.NetworkProtocolNumber}, ProtocolNumber, r.id, ep, ep.portFlags, tcpip.NICID(ep.ops.GetBindToDevice())); err != nil {
diff --git a/pkg/tcpip/transport/udp/udp_test.go b/pkg/tcpip/transport/udp/udp_test.go
index c8da173f1..52403ed78 100644
--- a/pkg/tcpip/transport/udp/udp_test.go
+++ b/pkg/tcpip/transport/udp/udp_test.go
@@ -967,7 +967,7 @@ func testFailingWrite(c *testContext, flow testFlow, wantErr *tcpip.Error) {
writeDstAddr := flow.mapAddrIfApplicable(h.dstAddr.Addr)
payload := buffer.View(newPayload())
- _, _, gotErr := c.ep.Write(tcpip.SlicePayload(payload), tcpip.WriteOptions{
+ _, gotErr := c.ep.Write(tcpip.SlicePayload(payload), tcpip.WriteOptions{
To: &tcpip.FullAddress{Addr: writeDstAddr, Port: h.dstAddr.Port},
})
c.checkEndpointWriteStats(1, epstats, gotErr)
@@ -1008,7 +1008,7 @@ func testWriteNoVerify(c *testContext, flow testFlow, setDest bool) buffer.View
}
}
payload := buffer.View(newPayload())
- n, _, err := c.ep.Write(tcpip.SlicePayload(payload), writeOpts)
+ n, err := c.ep.Write(tcpip.SlicePayload(payload), writeOpts)
if err != nil {
c.t.Fatalf("Write failed: %s", err)
}
@@ -1184,7 +1184,7 @@ func TestWriteOnConnectedInvalidPort(t *testing.T) {
To: &tcpip.FullAddress{Addr: stackAddr, Port: invalidPort},
}
payload := buffer.View(newPayload())
- n, _, err := c.ep.Write(tcpip.SlicePayload(payload), writeOpts)
+ n, err := c.ep.Write(tcpip.SlicePayload(payload), writeOpts)
if err != nil {
c.t.Fatalf("c.ep.Write(...) = %+s, want nil", err)
}
@@ -2317,8 +2317,6 @@ func (c *testContext) checkEndpointWriteStats(incr uint64, want tcpip.TransportE
want.WriteErrors.WriteClosed.IncrementBy(incr)
case tcpip.ErrInvalidEndpointState:
want.WriteErrors.InvalidEndpointState.IncrementBy(incr)
- case tcpip.ErrNoLinkAddress:
- want.SendErrors.NoLinkAddr.IncrementBy(incr)
case tcpip.ErrNoRoute, tcpip.ErrBroadcastDisabled, tcpip.ErrNetworkUnreachable:
want.SendErrors.NoRoute.IncrementBy(incr)
default:
@@ -2510,20 +2508,20 @@ func TestOutgoingSubnetBroadcast(t *testing.T) {
expectedErrWithoutBcastOpt = nil
}
- if n, _, err := ep.Write(data, opts); err != expectedErrWithoutBcastOpt {
- t.Fatalf("got ep.Write(_, _) = (%d, _, %v), want = (_, _, %v)", n, err, expectedErrWithoutBcastOpt)
+ if n, err := ep.Write(data, opts); err != expectedErrWithoutBcastOpt {
+ t.Fatalf("got ep.Write(_, %#v) = (%d, %s), want = (_, %s)", opts, n, err, expectedErrWithoutBcastOpt)
}
ep.SocketOptions().SetBroadcast(true)
- if n, _, err := ep.Write(data, opts); err != nil {
- t.Fatalf("got ep.Write(_, _) = (%d, _, %s), want = (_, _, nil)", n, err)
+ if n, err := ep.Write(data, opts); err != nil {
+ t.Fatalf("got ep.Write(_, %#v) = (%d, %s), want = (_, nil)", opts, n, err)
}
ep.SocketOptions().SetBroadcast(false)
- if n, _, err := ep.Write(data, opts); err != expectedErrWithoutBcastOpt {
- t.Fatalf("got ep.Write(_, _) = (%d, _, %v), want = (_, _, %v)", n, err, expectedErrWithoutBcastOpt)
+ if n, err := ep.Write(data, opts); err != expectedErrWithoutBcastOpt {
+ t.Fatalf("got ep.Write(_, %#v) = (%d, %s), want = (_, %s)", opts, n, err, expectedErrWithoutBcastOpt)
}
})
}