From de51129e33a5fe4fad3da172539e9be640d39211 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 29 Jan 2021 18:54:19 +0100 Subject: device: use int64 instead of atomic.Value for time stamp Signed-off-by: Jason A. Donenfeld --- device/alignment_test.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ device/device.go | 16 +++--------- device/peer_test.go | 43 ------------------------------- 3 files changed, 70 insertions(+), 56 deletions(-) create mode 100644 device/alignment_test.go delete mode 100644 device/peer_test.go (limited to 'device') diff --git a/device/alignment_test.go b/device/alignment_test.go new file mode 100644 index 0000000..5587cbe --- /dev/null +++ b/device/alignment_test.go @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. + */ + +package device + +import ( + "reflect" + "testing" + "unsafe" +) + +func checkAlignment(t *testing.T, name string, offset uintptr) { + t.Helper() + if offset%8 != 0 { + t.Errorf("offset of %q within struct is %d bytes, which does not align to 64-bit word boundaries (missing %d bytes). Atomic operations will crash on 32-bit systems.", name, offset, 8-(offset%8)) + } +} + +// TestPeerAlignment checks that atomically-accessed fields are +// aligned to 64-bit boundaries, as required by the atomic package. +// +// Unfortunately, violating this rule on 32-bit platforms results in a +// hard segfault at runtime. +func TestPeerAlignment(t *testing.T) { + var p Peer + + typ := reflect.TypeOf(&p).Elem() + t.Logf("Peer type size: %d, with fields:", typ.Size()) + for i := 0; i < typ.NumField(); i++ { + field := typ.Field(i) + t.Logf("\t%30s\toffset=%3v\t(type size=%3d, align=%d)", + field.Name, + field.Offset, + field.Type.Size(), + field.Type.Align(), + ) + } + + checkAlignment(t, "Peer.stats", unsafe.Offsetof(p.stats)) + checkAlignment(t, "Peer.isRunning", unsafe.Offsetof(p.isRunning)) +} + + +// TestDeviceAlignment checks that atomically-accessed fields are +// aligned to 64-bit boundaries, as required by the atomic package. +// +// Unfortunately, violating this rule on 32-bit platforms results in a +// hard segfault at runtime. +func TestDeviceAlignment(t *testing.T) { + var d Device + + typ := reflect.TypeOf(&d).Elem() + t.Logf("Device type size: %d, with fields:", typ.Size()) + for i := 0; i < typ.NumField(); i++ { + field := typ.Field(i) + t.Logf("\t%30s\toffset=%3v\t(type size=%3d, align=%d)", + field.Name, + field.Offset, + field.Type.Size(), + field.Type.Align(), + ) + } + + checkAlignment(t, "Device.rate.underLoadUntil", unsafe.Offsetof(d.rate.underLoadUntil)) +} diff --git a/device/device.go b/device/device.go index fd88855..bac361e 100644 --- a/device/device.go +++ b/device/device.go @@ -62,7 +62,7 @@ type Device struct { cookieChecker CookieChecker rate struct { - underLoadUntil atomic.Value + underLoadUntil int64 limiter ratelimiter.Ratelimiter } @@ -245,20 +245,15 @@ func (device *Device) Down() { } func (device *Device) IsUnderLoad() bool { - // check if currently under load - now := time.Now() underLoad := len(device.queue.handshake.c) >= UnderLoadQueueSize if underLoad { - device.rate.underLoadUntil.Store(now.Add(UnderLoadAfterTime)) + atomic.StoreInt64(&device.rate.underLoadUntil, now.Add(UnderLoadAfterTime).UnixNano()) return true } - // check if recently under load - - until := device.rate.underLoadUntil.Load().(time.Time) - return until.After(now) + return atomic.LoadInt64(&device.rate.underLoadUntil) > now.UnixNano() } func (device *Device) SetPrivateKey(sk NoisePrivateKey) error { @@ -327,14 +322,9 @@ func NewDevice(tunDevice tun.Device, logger *Logger) *Device { mtu = DefaultMTU } device.tun.mtu = int32(mtu) - device.peers.keyMap = make(map[NoisePublicKey]*Peer) - device.rate.limiter.Init() - device.rate.underLoadUntil.Store(time.Time{}) - device.indexTable.Init() - device.PopulatePools() // create queues diff --git a/device/peer_test.go b/device/peer_test.go deleted file mode 100644 index 0020423..0000000 --- a/device/peer_test.go +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. - */ - -package device - -import ( - "reflect" - "testing" - "unsafe" -) - -func checkAlignment(t *testing.T, name string, offset uintptr) { - t.Helper() - if offset%8 != 0 { - t.Errorf("offset of %q within struct is %d bytes, which does not align to 64-bit word boundaries (missing %d bytes). Atomic operations will crash on 32-bit systems.", name, offset, 8-(offset%8)) - } -} - -// TestPeerAlignment checks that atomically-accessed fields are -// aligned to 64-bit boundaries, as required by the atomic package. -// -// Unfortunately, violating this rule on 32-bit platforms results in a -// hard segfault at runtime. -func TestPeerAlignment(t *testing.T) { - var p Peer - - typ := reflect.TypeOf(&p).Elem() - t.Logf("Peer type size: %d, with fields:", typ.Size()) - for i := 0; i < typ.NumField(); i++ { - field := typ.Field(i) - t.Logf("\t%30s\toffset=%3v\t(type size=%3d, align=%d)", - field.Name, - field.Offset, - field.Type.Size(), - field.Type.Align(), - ) - } - - checkAlignment(t, "Peer.stats", unsafe.Offsetof(p.stats)) - checkAlignment(t, "Peer.isRunning", unsafe.Offsetof(p.isRunning)) -} -- cgit v1.2.3-59-g8ed1b