From 1fe6db8c542431d3d6e229f563fefbd2f962fc81 Mon Sep 17 00:00:00 2001 From: Kevin Krakauer Date: Tue, 13 Jul 2021 11:18:15 -0700 Subject: netstack: atomically update buffer sizes Previously, two calls to set the send or receive buffer size could have raced and left state wherein: - The actual size depended on one call - The value returned by getsockopt() depended on the other PiperOrigin-RevId: 384508720 --- pkg/tcpip/socketops.go | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/pkg/tcpip/socketops.go b/pkg/tcpip/socketops.go index cc735c9ce..042326a3a 100644 --- a/pkg/tcpip/socketops.go +++ b/pkg/tcpip/socketops.go @@ -17,7 +17,6 @@ package tcpip import ( "sync/atomic" - "gvisor.dev/gvisor/pkg/atomicbitops" "gvisor.dev/gvisor/pkg/sync" ) @@ -208,16 +207,24 @@ type SocketOptions struct { // will not change. getSendBufferLimits GetSendBufferLimits `state:"manual"` + // sendBufSizeMu protects sendBufferSize and calls to + // handler.OnSetSendBufferSize. + sendBufSizeMu sync.Mutex `state:"nosave"` + // sendBufferSize determines the send buffer size for this socket. - sendBufferSize atomicbitops.AlignedAtomicInt64 + sendBufferSize int64 // getReceiveBufferLimits provides the handler to get the min, default and // max size for receive buffer. It is initialized at the creation time and // will not change. getReceiveBufferLimits GetReceiveBufferLimits `state:"manual"` + // receiveBufSizeMu protects receiveBufferSize and calls to + // handler.OnSetReceiveBufferSize. + receiveBufSizeMu sync.Mutex `state:"nosave"` + // receiveBufferSize determines the receive buffer size for this socket. - receiveBufferSize atomicbitops.AlignedAtomicInt64 + receiveBufferSize int64 // mu protects the access to the below fields. mu sync.Mutex `state:"nosave"` @@ -607,11 +614,6 @@ func (so *SocketOptions) SetBindToDevice(bindToDevice int32) Error { return nil } -// GetSendBufferSize gets value for SO_SNDBUF option. -func (so *SocketOptions) GetSendBufferSize() int64 { - return so.sendBufferSize.Load() -} - // SendBufferLimits returns the [min, max) range of allowable send buffer // sizes. func (so *SocketOptions) SendBufferLimits() (min, max int64) { @@ -619,18 +621,22 @@ func (so *SocketOptions) SendBufferLimits() (min, max int64) { return int64(limits.Min), int64(limits.Max) } +// GetSendBufferSize gets value for SO_SNDBUF option. +func (so *SocketOptions) GetSendBufferSize() int64 { + so.sendBufSizeMu.Lock() + defer so.sendBufSizeMu.Unlock() + return so.sendBufferSize +} + // SetSendBufferSize sets value for SO_SNDBUF option. notify indicates if the // stack handler should be invoked to set the send buffer size. func (so *SocketOptions) SetSendBufferSize(sendBufferSize int64, notify bool) { + so.sendBufSizeMu.Lock() + defer so.sendBufSizeMu.Unlock() if notify { sendBufferSize = so.handler.OnSetSendBufferSize(sendBufferSize) } - so.sendBufferSize.Store(sendBufferSize) -} - -// GetReceiveBufferSize gets value for SO_RCVBUF option. -func (so *SocketOptions) GetReceiveBufferSize() int64 { - return so.receiveBufferSize.Load() + so.sendBufferSize = sendBufferSize } // ReceiveBufferLimits returns the [min, max) range of allowable receive buffer @@ -640,12 +646,20 @@ func (so *SocketOptions) ReceiveBufferLimits() (min, max int64) { return int64(limits.Min), int64(limits.Max) } +// GetReceiveBufferSize gets value for SO_RCVBUF option. +func (so *SocketOptions) GetReceiveBufferSize() int64 { + so.receiveBufSizeMu.Lock() + defer so.receiveBufSizeMu.Unlock() + return so.receiveBufferSize +} + // SetReceiveBufferSize sets the value of the SO_RCVBUF option, optionally // notifying the owning endpoint. func (so *SocketOptions) SetReceiveBufferSize(receiveBufferSize int64, notify bool) { + so.receiveBufSizeMu.Lock() + defer so.receiveBufSizeMu.Unlock() if notify { - oldSz := so.receiveBufferSize.Load() - receiveBufferSize = so.handler.OnSetReceiveBufferSize(receiveBufferSize, oldSz) + receiveBufferSize = so.handler.OnSetReceiveBufferSize(receiveBufferSize, so.receiveBufferSize) } - so.receiveBufferSize.Store(receiveBufferSize) + so.receiveBufferSize = receiveBufferSize } -- cgit v1.2.3