aboutsummaryrefslogtreecommitdiff
path: root/device (follow)
Commit message (Collapse)AuthorAgeFilesLines
* device: add PeerStatsjs/peer-statsJosh Bleecher Snyder2021-01-261-0/+39
| | | | | | | | | | | | | Per-peer statistics are the sort of thing clients refresh very frequently, for UIs. They are available via UAPI, but the serialization and deserialization is quite heavy for frequent use. This commit adds a very cheap, direct means of retrieving peer stats. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: allow pipelining UAPI requestsJason A. Donenfeld2021-01-251-30/+36
| | | | | | The original spec ends with \n\n especially for this reason. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* device: serialize access to IpcSetOperationJosh Bleecher Snyder2021-01-252-0/+4
| | | | | | Interleaves IpcSetOperations would spell trouble. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: simplify handling of IPC set endpointJosh Bleecher Snyder2021-01-251-12/+4
| | | | Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove close processing fwmarkJosh Bleecher Snyder2021-01-251-11/+2
| | | | | | | Also, a behavior change: Stop treating a blank value as 0. It's not in the spec. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove unnecessary commentJosh Bleecher Snyder2021-01-251-1/+0
| | | | Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: introduce new IPC error message for unknown errorJosh Bleecher Snyder2021-01-251-2/+2
| | | | Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: correct IPC error number for I/O errorsJosh Bleecher Snyder2021-01-251-1/+4
| | | | Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: simplify IpcHandle error handlingJosh Bleecher Snyder2021-01-251-15/+6
| | | | | | | | | | Unify the handling of unexpected UAPI errors. The comment that says "should never happen" is incorrect; this could happen due to I/O errors. Correct it. Change error message capitalization for consistency. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: split IpcSetOperation into partsJosh Bleecher Snyder2021-01-251-204/+198
| | | | | | | | | | | | | | | | The goal of this change is to make the structure of IpcSetOperation easier to follow. IpcSetOperation contains a small state machine: It starts by configuring the device, then shifts to configuring one peer at a time. Having the code all in one giant method obscured that structure. Split out the parts into helper functions and encapsulate the peer state. This makes the overall structure more apparent. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: expand IPCErrorJosh Bleecher Snyder2021-01-251-51/+43
| | | | | | | | | | Expand IPCError to contain a wrapped error, and add a helper to make constructing such errors easier. Add a defer-based "log on returned error" to IpcSetOperation. This lets us simplify all of the error return paths. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove dead codeJosh Bleecher Snyder2021-01-251-6/+1
| | | | | | | | If device.NewPeer returns a nil error, then the returned peer is always non-nil. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: return errors from ipc scannerJosh Bleecher Snyder2021-01-251-1/+1
| | | | | | | | The code as written will drop any read errors on the floor. Fix that. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: allow compiling with Go 1.15Jason A. Donenfeld2021-01-201-1/+1
| | | | | | | | | Until we depend on Go 1.16 (which isn't released yet), alias our own variable to the private member of the net package. This will allow an easy find replace to make this go away when we eventually switch to 1.16. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* device: remove unused fields from DummyDatagram and DummyBindJosh Bleecher Snyder2021-01-201-3/+0
| | | | Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove unused trie test codeJosh Bleecher Snyder2021-01-201-20/+0
| | | | Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove unnecessary zeroingJosh Bleecher Snyder2021-01-201-5/+0
| | | | | | Newly allocated objects are already zeroed. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove QueueInboundElement.droppedJosh Bleecher Snyder2021-01-201-30/+5
| | | | | | | | | | | | Now that we block when enqueueing to the decryption queue, there is only one case in which we "drop" a inbound element, when decryption fails. We can use a simple, obvious, sync-free sentinel for that, elem.packet == nil. Also, we can return the message buffer to the pool slightly later, which further simplifies the code. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove QueueOutboundElement.droppedJosh Bleecher Snyder2021-01-201-23/+0
| | | | | | | If we block when enqueuing encryption elements to the queue, then we never drop them. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: check returned errors from NewPeer in TestNoiseHandshakeJosh Bleecher Snyder2021-01-201-2/+8
| | | | Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove selects from encrypt/decrypt/inbound/outbound enqueuingJosh Bleecher Snyder2021-01-202-38/+5
| | | | | | | Block instead. Backpressure here is fine, probably preferable. This reduces code complexity. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: put handshake buffer in pool in FlushPacketQueuesJosh Bleecher Snyder2021-01-201-1/+2
| | | | | | This appears to have been an oversight. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: use channel close to shut down and drain decryption channelJosh Bleecher Snyder2021-01-202-60/+50
| | | | | | | | | This is similar to commit e1fa1cc5560020e67d33aa7e74674853671cf0a0, but for the decryption channel. It is an alternative fix to f9f655567930a4cd78d40fa4ba0d58503335ae6a. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: receive: do not exit immediately on transient UDP receive errorsJason A. Donenfeld2021-01-081-6/+16
| | | | | | | | | | | | | | | | Some users report seeing lines like: > Routine: receive incoming IPv4 - stopped Popping up unexpectedly. Let's sleep and try again before failing, and also log the error, and perhaps we'll eventually understand this situation better in future versions. Because we have to distinguish between the socket being closed explicitly and whatever error this is, we bump the module to require Go 1.16. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* device: receive: drain decryption queue before exiting RoutineDecryptionJason A. Donenfeld2021-01-072-2/+18
| | | | | | | | | | | | It's possible for RoutineSequentialReceiver to try to lock an elem after RoutineDecryption has exited. Before this meant we didn't then unlock the elem, so the whole program deadlocked. As well, it looks like the flush code (which is now potentially unnecessary?) wasn't properly dropping the buffers for the not-already-dropped case. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* device: add latency and throughput benchmarksJosh Bleecher Snyder2021-01-071-0/+59
| | | | | | | | | | | These obviously don't perfectly capture real world performance, in which syscalls and network links have a significant impact. Nevertheless, they capture some of the internal performance factors, and they're easy and convenient to work with. Hat tip to Avery Pennarun for help designing the throughput benchmark. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: use LogLevelError for benchmarkingJosh Bleecher Snyder2021-01-071-1/+5
| | | | | | This keeps the output minimal and focused on the benchmark results. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: make test infrastructure usable with benchmarksJosh Bleecher Snyder2021-01-071-14/+14
| | | | | | Switch from *testing.T to testing.TB. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* all: use ++ to incrementJosh Bleecher Snyder2021-01-074-13/+13
| | | | | | Make the code slightly more idiomatic. No functional changes. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove unnecessary zeroingJosh Bleecher Snyder2021-01-071-1/+0
| | | | Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: call wg.Add outside the goroutineJosh Bleecher Snyder2021-01-072-3/+2
| | | | | | | | | | | One of the first rules of WaitGroups is that you call wg.Add outside of a goroutine, not inside it. Fix this embarrassing mistake. This prevents an extremely rare race condition (2 per 100,000 runs) which could occur when attempting to start a new peer concurrently with shutting down a device. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove QueueInboundElement leak with stopped peersJosh Bleecher Snyder2021-01-071-0/+2
| | | | | | | | | | | | | | | This is particularly problematic on mobile, where there is a fixed number of elements. If most of them leak, it'll impact performance; if all of them leak, the device will permanently deadlock. I have a test that detects element leaks, which is how I found this one. There are some remaining leaks that I have not yet tracked down, but this is the most prominent by far. I will commit the test when it passes reliably. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: simplify UAPI helper methodsJosh Bleecher Snyder2021-01-071-12/+5
| | | | | | | | | | | | | bufio is not required. strings.Builder is cheaper than bytes.Buffer for constructing strings. io.Writer is more flexible than io.StringWriter, and just as cheap (when used with io.WriteString). Run gofmt. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: fix alignment of peer stats memberJason A. Donenfeld2021-01-071-1/+2
| | | | | | | | This was shifted by 2 bytes when making persistent keepalive into a u32. Fix it by placing it after the aligned region. Fixes: e739ff7 ("device: fix persistent_keepalive_interval data races") Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* device: add UAPI helper methodsJason A. Donenfeld2021-01-071-2/+21
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* device: add missing colon to error lineJason A. Donenfeld2021-01-072-3/+3
| | | | | | | People are actually hitting this condition, so make it uniform. Also, change a printf into a println, to match the other conventions. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* device: fix error shadowing before log printBrad Fitzpatrick2021-01-071-4/+4
| | | | Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
* device: fix data race in peer.timersActiveJosh Bleecher Snyder2021-01-073-3/+6
| | | | | | | | | Found by the race detector and existing tests. To avoid introducing a lock into this hot path, calculate and cache whether any peers exist. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: fix races from changing private_keyJosh Bleecher Snyder2021-01-075-11/+32
| | | | | | | | | | Access keypair.sendNonce atomically. Eliminate one unnecessary initialization to zero. Mutate handshake.lastSentHandshake with the mutex held. Co-authored-by: David Anderson <danderson@tailscale.com> Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: always name *Queue*Element variables elemJosh Bleecher Snyder2021-01-073-26/+26
| | | | | | | | They're called elem in most places. Rename a few local variables to make it consistent. This makes it easier to grep the code for things like elem.Drop. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: use channel close to shut down and drain outbound channelJosh Bleecher Snyder2021-01-072-55/+34
| | | | | | | | | This is a similar treatment to the handling of the encryption channel found a few commits ago: Use the closing of the channel to manage goroutine lifetime and shutdown. It is considerably simpler because there is only a single writer. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: fix persistent_keepalive_interval data racesJosh Bleecher Snyder2021-01-075-9/+22
| | | | | Co-authored-by: David Anderson <danderson@tailscale.com> Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: use channel close to shut down and drain encryption channelJosh Bleecher Snyder2021-01-073-98/+170
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The new test introduced in this commit used to deadlock about 1% of the time. I believe that the deadlock occurs as follows: * The test completes, calling device.Close. * device.Close closes device.signals.stop. * RoutineEncryption stops. * The deferred function in RoutineEncryption drains device.queue.encryption. * RoutineEncryption exits. * A peer's RoutineNonce processes an element queued in peer.queue.nonce. * RoutineNonce puts that element into the outbound and encryption queues. * RoutineSequentialSender reads that elements from the outbound queue. * It waits for that element to get Unlocked by RoutineEncryption. * RoutineEncryption has already exited, so RoutineSequentialSender blocks forever. * device.RemoveAllPeers calls peer.Stop on all peers. * peer.Stop waits for peer.routines.stopping, which blocks forever. Rather than attempt to add even more ordering to the already complex centralized shutdown orchestration, this commit moves towards a data-flow-oriented shutdown. The device.queue.encryption gets closed when there will be no more writes to it. All device.queue.encryption readers always read until the channel is closed and then exit. We thus guarantee that any element that enters the encryption queue also exits it. This removes the need for central control of the lifetime of RoutineEncryption, removes the need to drain the encryption queue on shutdown, and simplifies RoutineEncryption. This commit also fixes a data race. When RoutineSequentialSender drains its queue on shutdown, it needs to lock the elem before operating on it, just as the main body does. The new test in this commit passed 50k iterations with the race detector enabled and 150k iterations with the race detector disabled, with no failures. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: simplify copying counter to nonceJosh Bleecher Snyder2021-01-071-12/+2
| | | | | | | | | | | | | | | | | | Since we already have it packed into a uint64 in a known byte order, write it back out again the same byte order instead of copying byte by byte. This should also generate more efficient code, because the compiler can do a single uint64 write, instead of eight bounds checks and eight byte writes. Due to a missed optimization, it actually generates a mishmash of smaller writes: 1 byte, 4 bytes, 2 bytes, 1 byte. This is https://golang.org/issue/41663. The code is still better than before, and will get better yet once that compiler bug gets fixed. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: add a helper to generate uapi configsJosh Bleecher Snyder2021-01-071-28/+45
| | | | | | | | This makes it easier to work with configs in tests. It'll see heavier use over upcoming commits; this commit only adds the infrastructure. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: use defer to simplify peer.NewTimerJosh Bleecher Snyder2021-01-071-2/+1
| | | | | | This also makes the lifetime of modifyingLock more prominent. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: accept any io.Reader in device.IpcSetOperationJosh Bleecher Snyder2021-01-071-2/+2
| | | | | | | | | | Any io.Reader will do, and there are no performance concerns here. This is technically backwards incompatible, but it is very unlikely to break any existing code. It is compatible with the existing uses in wireguard-{windows,android,apple} and also will allow us to slightly simplify it if desired. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: increase timeout in testsJosh Bleecher Snyder2021-01-071-2/+2
| | | | | | | | | When running many concurrent test processing using https://godoc.org/golang.org/x/tools/cmd/stress the processing sometimes cannot complete a ping in under 300ms. Increase the timeout to 5s to reduce the rate of false positives. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: prevent spurious errors while closing a deviceJosh Bleecher Snyder2021-01-071-0/+5
| | | | | | | | | | | | | | When closing a device, packets that are in flight can make it to SendBuffer, which then returns an error. Those errors add noise but no light; they do not reflect an actual problem. Adding the synchronization required to prevent this from occurring is currently expensive and error-prone. Instead, quietly drop such packets instead of returning an error. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
* device: remove starting waitgroupsJosh Bleecher Snyder2021-01-075-29/+1
| | | | | | | | | | | | | | | In each case, the starting waitgroup did nothing but ensure that the goroutine has launched. Nothing downstream depends on the order in which goroutines launch, and if the Go runtime scheduler is so broken that goroutines don't get launched reasonably promptly, we have much deeper problems. Given all that, simplify the code. Passed a race-enabled stress test 25,000 times without failure. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>