diff options
author | Ghanan Gowripalan <ghanan@google.com> | 2021-02-06 16:56:33 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-02-06 16:58:25 -0800 |
commit | 554c405e87285622e2d4019baf2c6a19b47f6007 (patch) | |
tree | e158183f320e97b7e06c8044e6f4290bb2eac86a /pkg | |
parent | 11ce8ba992aca85d28063d243d59b11d3bee99ba (diff) |
Synchronously send packets over pipe link endpoint
Before this change, packets were delivered asynchronously to the remote
end of a pipe. This was to avoid a deadlock during link resolution where
the stack would attempt to double-lock a mutex (see removed comments in
the parent commit for details).
As of https://github.com/google/gvisor/commit/4943347137, we do not hold
locks while sending link resolution probes so the deadlock will no
longer occur.
PiperOrigin-RevId: 356066224
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/tcpip/link/pipe/pipe.go | 44 |
1 files changed, 15 insertions, 29 deletions
diff --git a/pkg/tcpip/link/pipe/pipe.go b/pkg/tcpip/link/pipe/pipe.go index bbe84f220..21fb87757 100644 --- a/pkg/tcpip/link/pipe/pipe.go +++ b/pkg/tcpip/link/pipe/pipe.go @@ -46,6 +46,10 @@ type Endpoint struct { } func (e *Endpoint) deliverPackets(r stack.RouteInfo, proto tcpip.NetworkProtocolNumber, pkts stack.PacketBufferList) { + if !e.linked.IsAttached() { + return + } + // Note that the local address from the perspective of this endpoint is the // remote address from the perspective of the other end of the pipe // (e.linked). Similarly, the remote address from the perspective of this @@ -54,44 +58,26 @@ func (e *Endpoint) deliverPackets(r stack.RouteInfo, proto tcpip.NetworkProtocol // Deliver the packet in a new goroutine to escape this goroutine's stack and // avoid a deadlock when a packet triggers a response which leads the stack to // try and take a lock it already holds. - // - // As of writing, a deadlock may occur when performing link resolution as the - // neighbor table will send a solicitation while holding a lock and the - // response advertisement will be sent in the same stack that sent the - // solictation. When the response is received, the stack attempts to take the - // same lock it already took before sending the solicitation, leading to a - // deadlock. Basically, we attempt to lock the same lock twice in the same - // call stack. - // - // TODO(gvisor.dev/issue/5289): don't use a new goroutine once we support send - // and receive queues. - go func() { - for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() { - e.linked.dispatcher.DeliverNetworkPacket(r.LocalLinkAddress /* remote */, r.RemoteLinkAddress /* local */, proto, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Data: buffer.NewVectorisedView(pkt.Size(), pkt.Views()), - })) - } - }() + for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() { + e.linked.dispatcher.DeliverNetworkPacket(r.LocalLinkAddress /* remote */, r.RemoteLinkAddress /* local */, proto, stack.NewPacketBuffer(stack.PacketBufferOptions{ + Data: buffer.NewVectorisedView(pkt.Size(), pkt.Views()), + })) + } } // WritePacket implements stack.LinkEndpoint. func (e *Endpoint) WritePacket(r stack.RouteInfo, _ *stack.GSO, proto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error { - if e.linked.IsAttached() { - var pkts stack.PacketBufferList - pkts.PushBack(pkt) - e.deliverPackets(r, proto, pkts) - } - + var pkts stack.PacketBufferList + pkts.PushBack(pkt) + e.deliverPackets(r, proto, pkts) return nil } // WritePackets implements stack.LinkEndpoint. func (e *Endpoint) WritePackets(r stack.RouteInfo, _ *stack.GSO, pkts stack.PacketBufferList, proto tcpip.NetworkProtocolNumber) (int, tcpip.Error) { - if e.linked.IsAttached() { - e.deliverPackets(r, proto, pkts) - } - - return pkts.Len(), nil + n := pkts.Len() + e.deliverPackets(r, proto, pkts) + return n, nil } // Attach implements stack.LinkEndpoint. |