In #8650, we originally added a feature-flag for toggling the eBPF TURN router on and off at runtime. This later got removed again in #8681. What remained was a "caching system" of the config that the eBPF kernel and user space share with each other. This config was initialised to the default configuration. If the to-be-set config was the same as the current config, the config would not actually apply to the array that was shared with the eBPF kernel. At the time, we assumed that, if the config was not set in the kernel, the lookup in the array would yield `None` and we would fall back to the `Default` implementation of `Config`. This assumption was wrong. It appears that look-ups in the array always yield an element: all zeros. Initialising our config with all zeros yields the following:  Of course, if this range is not initialised correctly, we can never actually route packets arriving on allocation ports and with UDP checksumming turned off, all packets routed the other way will have an invalid checksum and therefore be dropped by the receiving host. Our integration test did not catch this because in there, we purposely disable UDP checksumming. That meant that the "caching" check in the `ebpf::Program` did not trigger and we actually did set a `Config` in the array, therefore initialising the allocation port range correctly and allowing the packet to be routed. To fix this, we remove this caching check again which means every `Config` we set on the eBPF program actually gets copied to the shared array. Originally, this caching check was introduced to avoid a syscall on every event-loop iteration as part of checking the feature-flag. Now that the feature-flag has been removed, we don't need to have this cache anymore.
Rust development guide
Firezone uses Rust for all data plane components. This directory contains the Linux and Windows clients, and low-level networking implementations related to STUN/TURN.
We target the last stable release of Rust using rust-toolchain.toml.
If you are using rustup, that is automatically handled for you.
Otherwise, ensure you have the latest stable version of Rust installed.
Reading Client logs
The Client logs are written as JSONL for machine-readability.
To make them more human-friendly, pipe them through jq like this:
cd path/to/logs # e.g. `$HOME/.cache/dev.firezone.client/data/logs` on Linux
cat *.log | jq -r '"\(.time) \(.severity) \(.message)"'
Resulting in, e.g.
2024-04-01T18:25:47.237661392Z INFO started log
2024-04-01T18:25:47.238193266Z INFO GIT_VERSION = 1.0.0-pre.11-35-gcc0d43531
2024-04-01T18:25:48.295243016Z INFO No token / actor_name on disk, starting in signed-out state
2024-04-01T18:25:48.295360641Z INFO null
Benchmarking on Linux
The recommended way for benchmarking any of the Rust components is Linux' perf utility.
For example, to attach to a running application, do:
- Ensure the binary you are profiling is compiled with the
releaseprofile. sudo perf record -g --freq 10000 --pid $(pgrep <your-binary>).- Run the speed test or whatever load-inducing task you want to measure.
sudo perf script > profile.perf- Open profiler.firefox.com and load
profile.perf
Instead of attaching to a process with --pid, you can also specify the path to executable directly.
That is useful if you want to capture perf data for a test or a micro-benchmark.