Files
tailscale/flake.nix
Jordan Whited 8fc6dca15e all: use ~128KiB packet buf for batched i/o
This commit bumps the wireguard-go dependency to incorporate changes to
the packet memory model and the tun.Device.Read and conn.ReceiveFunc I/O
interfaces. It updates their implementations accordingly.

These changes improve throughput in all measured benchmarks and reduce
peak RSS in six of eight cases. The two regressions will be addressed in
a follow-up commit that reduces peak RSS below the baseline measured at
1e69418. That work is kept separate to simplify review.

The following throughput and peak RSS benchmarks were performed with
iperf3 between two Intel i5-12400 nodes running Ubuntu 24.04 (Linux 6.8).

The UDP benchmarks did not use UDP GSO on the sender, so they were
roughly equivalent to single packet I/O through wireguard-go.

TCP/1 signifies one TCP stream; TCP/128 signifies 128 parallel TCP
streams.

Throughput (Mb/s)
  Test     1e69418  After  Change
  TCP/1    10,371  11,354   +9.5%
  TCP/128   7,886   8,404   +6.6%
  UDP/1     2,111   2,853  +35.1%
  UDP/128   1,747   2,235  +28.0%

Peak memory (VmHWM, kB)
  Test     Side   1e69418    After   Change
  TCP/1    TX      98,240   52,596   -46.5%
           RX     287,748   73,384   -74.5%
  TCP/128  TX     101,196   52,812   -47.8%
           RX     290,420   63,620   -78.1%
  UDP/1    TX      58,864  160,840  +173.2%
           RX     137,516   49,900   -63.7%
  UDP/128  TX      66,148  116,096   +75.5%
           RX     154,384   56,556   -63.4%

Updates tailscale/corp#46716
Updates tailscale/corp#22467
Updates tailscale/corp#36989
Updates tailscale/corp#37878

Signed-off-by: Jordan Whited <jordan@tailscale.com>
2026-09-04 09:32:55 -07:00

176 lines
6.7 KiB
Nix

# flake.nix describes a Nix source repository that provides
# development builds of Tailscale and the fork of the Go compiler
# toolchain that Tailscale maintains. It also provides a development
# environment for working on tailscale, for use with "nix develop".
#
# For more information about this and why this file is useful, see:
# https://wiki.nixos.org/wiki/Flakes
#
# Also look into direnv: https://direnv.net/, this can make it so that you can
# automatically get your environment set up when you change folders into the
# project.
#
# WARNING: currently, the packages provided by this flake are brittle,
# and importing this flake into your own Nix configs is likely to
# leave you with broken builds periodically.
#
# The issue is that building Tailscale binaries uses the buildGoModule
# helper from nixpkgs. This helper demands to know the content hash of
# all of the Go dependencies of this repo, in the form of a Nix SRI
# hash. This hash isn't automatically kept in sync with changes made
# to go.mod yet, and so every time we update go.mod while hacking on
# Tailscale, this flake ends up with a broken build due to hash
# mismatches.
#
# Right now, this flake is intended for use by Tailscale developers,
# who are aware of this mismatch and willing to live with it. At some
# point, we'll add automation to keep the hashes more in sync, at
# which point this caveat should go away.
#
# See https://github.com/tailscale/tailscale/issues/6845 for tracking
# how to fix this mismatch.
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
systems.url = "github:nix-systems/default";
# Used by shell.nix as a compat shim.
flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
};
outputs = {
self,
nixpkgs,
systems,
flake-compat,
}: let
goVersion = nixpkgs.lib.fileContents ./go.toolchain.version;
toolChainRev = nixpkgs.lib.fileContents ./go.toolchain.rev;
flakeHashes = builtins.fromJSON (builtins.readFile ./flakehashes.json);
gitHash = flakeHashes.toolchain.sri;
eachSystem = f:
nixpkgs.lib.genAttrs (import systems) (system:
f (import nixpkgs {
system = system;
overlays = [
(final: prev: {
go_1_27 = prev.go_1_27.overrideAttrs (old: {
version = goVersion;
src = prev.fetchFromGitHub {
owner = "tailscale";
repo = "go";
rev = toolChainRev;
sha256 = gitHash;
};
# The Tailscale Go fork carries a placeholder in
# src/runtime/debug/mod.go that must be replaced with
# the actual toolchain git rev at build time. Without
# this, binaries report an empty tailscale.toolchain.rev
# and the runtime assertion in
# assert_ts_toolchain_match.go panics.
postPatch =
(old.postPatch or "")
+ ''
substituteInPlace src/runtime/debug/mod.go \
--replace-fail "TAILSCALE_GIT_REV_TO_BE_REPLACED_AT_BUILD_TIME" "${toolChainRev}"
'';
});
})
];
}));
tailscaleRev = self.rev or "";
in {
# tailscale takes a nixpkgs package set, and builds Tailscale from
# the same commit as this flake. IOW, it provides "tailscale built
# from HEAD", where HEAD is "whatever commit you imported the
# flake at".
#
# This is currently unfortunately brittle, because we have to
# specify vendorHash, and that sha changes any time we alter
# go.mod. We don't want to force a nix dependency on everyone
# hacking on Tailscale, so this flake is likely to have broken
# builds periodically until someone comes through and manually
# fixes them up. I sure wish there was a way to express "please
# just trust the local go.mod, vendorHash has no benefit here",
# but alas.
#
# So really, this flake is for tailscale devs to dogfood with, if
# you're an end user you should be prepared for this flake to not
# build periodically.
packages = eachSystem (pkgs: rec {
default = pkgs.buildGo127Module {
name = "tailscale";
pname = "tailscale";
src = ./.;
vendorHash = flakeHashes.vendor.sri;
nativeBuildInputs = [pkgs.makeWrapper pkgs.installShellFiles];
ldflags = ["-X tailscale.com/version.gitCommitStamp=${tailscaleRev}"];
env.CGO_ENABLED = 0;
subPackages = [
"cmd/tailscale"
"cmd/tailscaled"
"cmd/tsidp"
];
doCheck = false;
# NOTE: We strip the ${PORT} and $FLAGS because they are unset in the
# environment and cause issues (specifically the unset PORT). At some
# point, there should be a NixOS module that allows configuration of these
# things, but for now, we hardcode the default of port 41641 (taken from
# ./cmd/tailscaled/tailscaled.defaults).
postInstall =
pkgs.lib.optionalString pkgs.stdenv.isLinux ''
wrapProgram $out/bin/tailscaled --prefix PATH : ${pkgs.lib.makeBinPath [pkgs.iproute2 pkgs.iptables pkgs.getent pkgs.shadow]}
wrapProgram $out/bin/tailscale --suffix PATH : ${pkgs.lib.makeBinPath [pkgs.procps]}
sed -i \
-e "s#/usr/sbin#$out/bin#" \
-e "/^EnvironmentFile/d" \
-e 's/''${PORT}/41641/' \
-e 's/$FLAGS//' \
./cmd/tailscaled/tailscaled.service
install -D -m0444 -t $out/lib/systemd/system ./cmd/tailscaled/tailscaled.service
''
+ pkgs.lib.optionalString (pkgs.stdenv.buildPlatform.canExecute pkgs.stdenv.hostPlatform) ''
installShellCompletion --cmd tailscale \
--bash <($out/bin/tailscale completion bash) \
--fish <($out/bin/tailscale completion fish) \
--zsh <($out/bin/tailscale completion zsh)
'';
};
tailscale = default;
});
devShells = eachSystem (pkgs: {
default = pkgs.mkShell {
packages = with pkgs; [
curl
git
gopls
gotools
graphviz
perl
go_1_27
yarn
# qemu and e2fsprogs are needed for natlab
qemu
e2fsprogs
# mtools (mcopy) and dtc are needed by the `tsapp-qemu-pi`
# Makefile target that boots the Tailscale appliance under qemu.
mtools
dtc
# awscli2 is used by gokrazy/build.go to import and register the
# Tailscale appliance AMI.
awscli2.out
];
};
});
};
}
# nix-direnv cache busting line: sha256-edmocquubPBqaakW8/TfQTLZS48HR7SOcWjYiLeJGLY=