netstack: switch from sync/atomic to atomicbitops for 32 bit values

PiperOrigin-RevId: 444446109
This commit is contained in:
Kevin Krakauer
2022-04-25 20:41:26 -07:00
committed by gVisor bot
parent fc5af87b46
commit ef9e8d9131
45 changed files with 265 additions and 281 deletions
+3 -4
View File
@@ -16,7 +16,6 @@ package control
import (
"fmt"
"sync/atomic"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/strace"
@@ -83,11 +82,11 @@ func (l *Logging) Change(args *LoggingArgs, code *int) error {
if args.SetLogPackets {
if args.LogPackets {
atomic.StoreUint32(&sniffer.LogPackets, 1)
sniffer.LogPackets.Store(1)
} else {
atomic.StoreUint32(&sniffer.LogPackets, 0)
sniffer.LogPackets.Store(0)
}
log.Infof("LogPackets set to: %v", atomic.LoadUint32(&sniffer.LogPackets))
log.Infof("LogPackets set to: %v", sniffer.LogPackets.Load())
}
if args.SetStrace {
+1
View File
@@ -14,6 +14,7 @@ go_library(
],
visibility = ["//visibility:public"],
deps = [
"//pkg/atomicbitops",
"//pkg/sync",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
+3 -5
View File
@@ -42,9 +42,9 @@ package fdbased
import (
"fmt"
"sync/atomic"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
@@ -223,9 +223,7 @@ type Options struct {
// Since fanoutID must be unique within the network namespace, we start with
// the PID to avoid collisions. The only way to be sure of avoiding collisions
// is to run in a new network namespace.
//
// Must be accessed using atomic operations.
var fanoutID int32 = int32(unix.Getpid())
var fanoutID atomicbitops.Int32 = atomicbitops.FromInt32(int32(unix.Getpid()))
// New creates a new fd-based endpoint.
//
@@ -282,7 +280,7 @@ func New(opts *Options) (stack.LinkEndpoint, error) {
// Increment fanoutID to ensure that we don't re-use the same fanoutID for
// the next endpoint.
fid := atomic.AddInt32(&fanoutID, 1)
fid := fanoutID.Add(1)
// Create per channel dispatchers.
for _, fd := range opts.FDs {
+3 -3
View File
@@ -19,10 +19,10 @@ package fdbased
import (
"fmt"
"sync/atomic"
"unsafe"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/atomicbitops"
)
// tPacketHdrlen is the TPACKET_HDRLEN variable defined in <linux/if_packet.h>.
@@ -34,7 +34,7 @@ var tPacketHdrlen = tPacketAlign(unsafe.Sizeof(tPacketHdr{}) + unsafe.Sizeof(uni
func (t tPacketHdr) tpStatus() uint32 {
hdr := unsafe.Pointer(&t[0])
statusPtr := unsafe.Pointer(uintptr(hdr) + uintptr(tpStatusOffset))
return atomic.LoadUint32((*uint32)(statusPtr))
return (*atomicbitops.Uint32)(statusPtr).Load()
}
// setTPStatus set's the frame status to the provided status.
@@ -43,7 +43,7 @@ func (t tPacketHdr) tpStatus() uint32 {
func (t tPacketHdr) setTPStatus(status uint32) {
hdr := unsafe.Pointer(&t[0])
statusPtr := unsafe.Pointer(uintptr(hdr) + uintptr(tpStatusOffset))
atomic.StoreUint32((*uint32)(statusPtr), status)
(*atomicbitops.Uint32)(statusPtr).Store(status)
}
func newPacketMMapDispatcher(fd int, e *endpoint) (linkDispatcher, error) {
+1
View File
@@ -9,6 +9,7 @@ go_library(
],
visibility = ["//visibility:public"],
deps = [
"//pkg/atomicbitops",
"//pkg/sleep",
"//pkg/sync",
"//pkg/tcpip",
+4 -6
View File
@@ -18,8 +18,7 @@
package fifo
import (
"sync/atomic"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/sleep"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
@@ -44,8 +43,7 @@ type discipline struct {
wg sync.WaitGroup
dispatchers []queueDispatcher
// +checkatomic
closed int32
closed atomicbitops.Int32
}
// queueDispatcher is responsible for dispatching all outbound packets in its
@@ -134,7 +132,7 @@ func (qd *queueDispatcher) dispatchLoop() {
// - pkt.GSOOptions
// - pkt.NetworkProtocolNumber
func (d *discipline) WritePacket(pkt *stack.PacketBuffer) tcpip.Error {
if atomic.LoadInt32(&d.closed) == qDiscClosed {
if d.closed.Load() == qDiscClosed {
return &tcpip.ErrClosedForSend{}
}
qd := &d.dispatchers[int(pkt.Hash)%len(d.dispatchers)]
@@ -154,7 +152,7 @@ func (d *discipline) WritePacket(pkt *stack.PacketBuffer) tcpip.Error {
}
func (d *discipline) Close() {
atomic.StoreInt32(&d.closed, qDiscClosed)
d.closed.Store(qDiscClosed)
for i := range d.dispatchers {
d.dispatchers[i].closeWaker.Assert()
}
+1
View File
@@ -18,6 +18,7 @@ go_library(
"//visibility:public",
],
deps = [
"//pkg/atomicbitops",
"//pkg/cleanup",
"//pkg/eventfd",
"//pkg/log",
+2
View File
@@ -10,6 +10,7 @@ go_library(
],
visibility = ["//visibility:public"],
deps = [
"//pkg/atomicbitops",
"//pkg/log",
"//pkg/tcpip/link/sharedmem/pipe",
],
@@ -22,6 +23,7 @@ go_test(
],
library = ":queue",
deps = [
"//pkg/atomicbitops",
"//pkg/tcpip/link/sharedmem/pipe",
],
)
+11 -10
View File
@@ -19,6 +19,7 @@ import (
"reflect"
"testing"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/tcpip/link/sharedmem/pipe"
)
@@ -35,7 +36,7 @@ func TestBasicTxQueue(t *testing.T) {
txp.Init(pb2)
var q Tx
var state uint32
var state atomicbitops.Uint32
q.Init(pb1, pb2, &state)
// Enqueue two buffers.
@@ -204,7 +205,7 @@ func TestBadTxCompletion(t *testing.T) {
txp.Init(pb2)
var q Tx
var state uint32
var state atomicbitops.Uint32
q.Init(pb1, pb2, &state)
// Post a completion that is too short, and check that it is ignored.
@@ -320,7 +321,7 @@ func TestFillTxPipe(t *testing.T) {
txp.Init(pb2)
var q Tx
var state uint32
var state atomicbitops.Uint32
q.Init(pb1, pb2, &state)
// Transmit twice, which should fill the tx pipe.
@@ -389,7 +390,7 @@ func TestLotsOfTransmissions(t *testing.T) {
txp.Init(pb2)
var q Tx
var state uint32
var state atomicbitops.Uint32
q.Init(pb1, pb2, &state)
// Prepare packet with two buffers.
@@ -495,13 +496,13 @@ func TestRxEnableNotification(t *testing.T) {
pb1 := make([]byte, 100)
pb2 := make([]byte, 100)
var state uint32
var state atomicbitops.Uint32
var q Rx
q.Init(pb1, pb2, &state)
q.EnableNotification()
if state != EventFDEnabled {
t.Fatalf("Bad value in shared state: got %v, want %v", state, EventFDEnabled)
if state.Load() != EventFDEnabled {
t.Fatalf("Bad value in shared state: got %v, want %v", state.Load(), EventFDEnabled)
}
}
@@ -510,12 +511,12 @@ func TestRxDisableNotification(t *testing.T) {
pb1 := make([]byte, 100)
pb2 := make([]byte, 100)
var state uint32
var state atomicbitops.Uint32
var q Rx
q.Init(pb1, pb2, &state)
q.DisableNotification()
if state != EventFDDisabled {
t.Fatalf("Bad value in shared state: got %v, want %v", state, EventFDDisabled)
if state.Load() != EventFDDisabled {
t.Fatalf("Bad value in shared state: got %v, want %v", state.Load(), EventFDDisabled)
}
}
+5 -5
View File
@@ -18,8 +18,8 @@ package queue
import (
"encoding/binary"
"sync/atomic"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/tcpip/link/sharedmem/pipe"
)
@@ -77,12 +77,12 @@ type RxBuffer struct {
type Rx struct {
tx pipe.Tx
rx pipe.Rx
sharedEventFDState *uint32
sharedEventFDState *atomicbitops.Uint32
}
// Init initializes the receive queue with the given pipes, and shared state
// pointer -- the latter is used to enable/disable eventfd notifications.
func (r *Rx) Init(tx, rx []byte, sharedEventFDState *uint32) {
func (r *Rx) Init(tx, rx []byte, sharedEventFDState *atomicbitops.Uint32) {
r.sharedEventFDState = sharedEventFDState
r.tx.Init(tx)
r.rx.Init(rx)
@@ -91,13 +91,13 @@ func (r *Rx) Init(tx, rx []byte, sharedEventFDState *uint32) {
// EnableNotification updates the shared state such that the peer will notify
// the eventfd when there are packets to be dequeued.
func (r *Rx) EnableNotification() {
atomic.StoreUint32(r.sharedEventFDState, EventFDEnabled)
r.sharedEventFDState.Store(EventFDEnabled)
}
// DisableNotification updates the shared state such that the peer will not
// notify the eventfd.
func (r *Rx) DisableNotification() {
atomic.StoreUint32(r.sharedEventFDState, EventFDDisabled)
r.sharedEventFDState.Store(EventFDDisabled)
}
// PostedBuffersLimit returns the maximum number of buffers that can be posted
+4 -4
View File
@@ -16,8 +16,8 @@ package queue
import (
"encoding/binary"
"sync/atomic"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/tcpip/link/sharedmem/pipe"
)
@@ -52,11 +52,11 @@ type TxBuffer struct {
type Tx struct {
tx pipe.Tx
rx pipe.Rx
sharedEventFDState *uint32
sharedEventFDState *atomicbitops.Uint32
}
// Init initializes the transmit queue with the given pipes.
func (t *Tx) Init(tx, rx []byte, sharedEventFDState *uint32) {
func (t *Tx) Init(tx, rx []byte, sharedEventFDState *atomicbitops.Uint32) {
t.tx.Init(tx)
t.rx.Init(rx)
t.sharedEventFDState = sharedEventFDState
@@ -66,7 +66,7 @@ func (t *Tx) Init(tx, rx []byte, sharedEventFDState *uint32) {
// peer of events (eg. packet transmit etc).
func (t *Tx) NotificationsEnabled() bool {
// Notifications are considered enabled unless explicitly disabled.
return atomic.LoadUint32(t.sharedEventFDState) != EventFDDisabled
return t.sharedEventFDState.Load() != EventFDDisabled
}
// Enqueue queues the given linked list of buffers for transmission as one
+4 -5
View File
@@ -18,9 +18,8 @@
package sharedmem
import (
"sync/atomic"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/eventfd"
"gvisor.dev/gvisor/pkg/tcpip/link/sharedmem/queue"
)
@@ -111,7 +110,7 @@ func (r *rx) notify() {
// that were read as well.
//
// This function will block if there aren't any available packets.
func (r *rx) postAndReceive(b []queue.RxBuffer, stopRequested *uint32) ([]queue.RxBuffer, uint32) {
func (r *rx) postAndReceive(b []queue.RxBuffer, stopRequested *atomicbitops.Uint32) ([]queue.RxBuffer, uint32) {
// Post the buffers first. If we cannot post, sleep until we can. We
// never post more than will fit concurrently, so it's safe to wait
// until enough room is available.
@@ -119,7 +118,7 @@ func (r *rx) postAndReceive(b []queue.RxBuffer, stopRequested *uint32) ([]queue.
r.q.EnableNotification()
for !r.q.PostBuffers(b) {
r.eventFD.Wait()
if atomic.LoadUint32(stopRequested) != 0 {
if stopRequested.Load() != 0 {
r.q.DisableNotification()
return nil, 0
}
@@ -143,7 +142,7 @@ func (r *rx) postAndReceive(b []queue.RxBuffer, stopRequested *uint32) ([]queue.
// Wait for notification.
r.eventFD.Wait()
if atomic.LoadUint32(stopRequested) != 0 {
if stopRequested.Load() != 0 {
r.q.DisableNotification()
return nil, 0
}
+4 -5
View File
@@ -18,9 +18,8 @@
package sharedmem
import (
"sync/atomic"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/cleanup"
"gvisor.dev/gvisor/pkg/eventfd"
"gvisor.dev/gvisor/pkg/tcpip/link/sharedmem/pipe"
@@ -47,7 +46,7 @@ type serverRx struct {
// sharedEventFDState is the memory region in sharedData used to enable
// disable notifications on eventFD.
sharedEventFDState *uint32
sharedEventFDState *atomicbitops.Uint32
}
// init initializes all state needed by the serverTx queue based on the
@@ -112,13 +111,13 @@ func (s *serverRx) cleanup() {
// EnableNotification updates the shared state such that the peer will notify
// the eventfd when there are packets to be dequeued.
func (s *serverRx) EnableNotification() {
atomic.StoreUint32(s.sharedEventFDState, queue.EventFDEnabled)
s.sharedEventFDState.Store(queue.EventFDEnabled)
}
// DisableNotification updates the shared state such that the peer will not
// notify the eventfd.
func (s *serverRx) DisableNotification() {
atomic.StoreUint32(s.sharedEventFDState, queue.EventFDDisabled)
s.sharedEventFDState.Store(queue.EventFDDisabled)
}
// completionNotificationSize is size in bytes of a completion notification sent
+3 -4
View File
@@ -18,9 +18,8 @@
package sharedmem
import (
"sync/atomic"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/cleanup"
"gvisor.dev/gvisor/pkg/eventfd"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
@@ -50,7 +49,7 @@ type serverTx struct {
// sharedEventFDState is the memory region in sharedData used to enable/disable
// notifications on eventFD.
sharedEventFDState *uint32
sharedEventFDState *atomicbitops.Uint32
}
// init initializes all tstate needed by the serverTx queue based on the
@@ -198,7 +197,7 @@ func (s *serverTx) transmit(views []buffer.View) bool {
func (s *serverTx) notificationsEnabled() bool {
// notifications are considered to be enabled unless explicitly disabled.
return atomic.LoadUint32(s.sharedEventFDState) != queue.EventFDDisabled
return s.sharedEventFDState.Load() != queue.EventFDDisabled
}
func (s *serverTx) notify() {
+6 -7
View File
@@ -25,8 +25,8 @@ package sharedmem
import (
"fmt"
"sync/atomic"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/eventfd"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sync"
@@ -167,9 +167,8 @@ type endpoint struct {
// rx is the receive queue.
rx rx
// stopRequested is to be accessed atomically only, and determines if
// the worker goroutines should stop.
stopRequested uint32
// stopRequested determines whether the worker goroutines should stop.
stopRequested atomicbitops.Uint32
// Wait group used to indicate that all workers have stopped.
completed sync.WaitGroup
@@ -236,7 +235,7 @@ func New(opts Options) (stack.LinkEndpoint, error) {
func (e *endpoint) Close() {
// Tell dispatch goroutine to stop, then write to the eventfd so that
// it wakes up in case it's sleeping.
atomic.StoreUint32(&e.stopRequested, 1)
e.stopRequested.Store(1)
e.rx.eventFD.Notify()
// Cleanup the queues inline if the worker hasn't started yet; we also
@@ -261,7 +260,7 @@ func (e *endpoint) Wait() {
// reads packets from the rx queue.
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.mu.Lock()
if !e.workerStarted && atomic.LoadUint32(&e.stopRequested) == 0 {
if !e.workerStarted && e.stopRequested.Load() == 0 {
e.workerStarted = true
e.completed.Add(1)
@@ -396,7 +395,7 @@ func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) {
// Read in a loop until a stop is requested.
var rxb []queue.RxBuffer
for atomic.LoadUint32(&e.stopRequested) == 0 {
for e.stopRequested.Load() == 0 {
var n uint32
rxb, n = e.rx.postAndReceive(rxb, &e.stopRequested)
+6 -8
View File
@@ -18,8 +18,7 @@
package sharedmem
import (
"sync/atomic"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
@@ -44,9 +43,8 @@ type serverEndpoint struct {
// rx is the receive queue.
rx serverRx
// stopRequested is to be accessed atomically only, and determines if the
// worker goroutines should stop.
stopRequested uint32
// stopRequested determines whether the worker goroutines should stop.
stopRequested atomicbitops.Uint32
// Wait group used to indicate that all workers have stopped.
completed sync.WaitGroup
@@ -124,7 +122,7 @@ func NewServerEndpoint(opts Options) (stack.LinkEndpoint, error) {
func (e *serverEndpoint) Close() {
// Tell dispatch goroutine to stop, then write to the eventfd so that it wakes
// up in case it's sleeping.
atomic.StoreUint32(&e.stopRequested, 1)
e.stopRequested.Store(1)
e.rx.eventFD.Notify()
// Cleanup the queues inline if the worker hasn't started yet; we also know it
@@ -149,7 +147,7 @@ func (e *serverEndpoint) Wait() {
// reads packets from the rx queue.
func (e *serverEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
e.mu.Lock()
if !e.workerStarted && atomic.LoadUint32(&e.stopRequested) == 0 {
if !e.workerStarted && e.stopRequested.Load() == 0 {
e.workerStarted = true
e.completed.Add(1)
if e.peerFD >= 0 {
@@ -277,7 +275,7 @@ func (e *serverEndpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.E
// dispatchLoop reads packets from the rx queue in a loop and dispatches them
// to the network stack.
func (e *serverEndpoint) dispatchLoop(d stack.NetworkDispatcher) {
for atomic.LoadUint32(&e.stopRequested) == 0 {
for e.stopRequested.Load() == 0 {
b := e.rx.receive()
if b == nil {
e.rx.EnableNotification()
+3 -2
View File
@@ -20,13 +20,14 @@ import (
"unsafe"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/memutil"
)
// sharedDataPointer converts the shared data slice into a pointer so that it
// can be used in atomic operations.
func sharedDataPointer(sharedData []byte) *uint32 {
return (*uint32)(unsafe.Pointer(&sharedData[0:4][0]))
func sharedDataPointer(sharedData []byte) *atomicbitops.Uint32 {
return (*atomicbitops.Uint32)(unsafe.Pointer(&sharedData[0:4][0]))
}
// getBuffer returns a memory region mapped to the full contents of the given
+1
View File
@@ -10,6 +10,7 @@ go_library(
],
visibility = ["//visibility:public"],
deps = [
"//pkg/atomicbitops",
"//pkg/log",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
+5 -9
View File
@@ -24,9 +24,9 @@ import (
"encoding/binary"
"fmt"
"io"
"sync/atomic"
"time"
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
@@ -38,16 +38,12 @@ import (
// LogPackets is a flag used to enable or disable packet logging via the log
// package. Valid values are 0 or 1.
//
// LogPackets must be accessed atomically.
var LogPackets uint32 = 1
var LogPackets atomicbitops.Uint32 = atomicbitops.FromUint32(1)
// LogPacketsToPCAP is a flag used to enable or disable logging packets to a
// pcap writer. Valid values are 0 or 1. A writer must have been specified when the
// sniffer was created for this flag to have effect.
//
// LogPacketsToPCAP must be accessed atomically.
var LogPacketsToPCAP uint32 = 1
var LogPacketsToPCAP atomicbitops.Uint32 = atomicbitops.FromUint32(1)
type endpoint struct {
nested.Endpoint
@@ -142,10 +138,10 @@ func (e *endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pk
func (e *endpoint) dumpPacket(dir direction, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
writer := e.writer
if writer == nil && atomic.LoadUint32(&LogPackets) == 1 {
if writer == nil && LogPackets.Load() == 1 {
logPacket(e.logPrefix, dir, protocol, pkt)
}
if writer != nil && atomic.LoadUint32(&LogPacketsToPCAP) == 1 {
if writer != nil && LogPacketsToPCAP.Load() == 1 {
packet := pcapPacket{
timestamp: time.Now(),
packet: pkt,
+1
View File
@@ -10,6 +10,7 @@ go_library(
],
visibility = ["//visibility:public"],
deps = [
"//pkg/atomicbitops",
"//pkg/sync",
"//pkg/tcpip",
"//pkg/tcpip/buffer",

Some files were not shown because too many files have changed in this diff Show More