02 / install
Build it. Attach it. Leave it idle.
clang compiles the XDP object, bpftool emits the skeleton, gcc links the daemon. Tests use SKB / bpf_prog_test_run and do not need a real NIC.
Requirements
- Linux 5.8+ with BTF (
/sys/kernel/btf/vmlinux) - clang, llvm, libbpf, bpftool, libelf, zlib
CAP_BPF+CAP_NET_ADMIN(root is fine)
Ubuntu 24.04
sudo apt install clang llvm libbpf-dev libelf-dev zlib1g-dev \
linux-tools-generic make gcc libtest-base-perl
git clone https://github.com/seawallnetworks/voidgate.git
cd voidgate
make
make test
make test runs the unit tests in t/unit/, then t/bin/run: the real daemon on a veth pair in private namespaces, driven by the Perl Test::Base suite in t/ (needs sudo). If a BPF change compiles but the daemon cannot load the object, the verifier rejected it — fix the program, do not weaken the test.
Run
sudo ./voidgate -c configs/voidgate.conf -i eth0
sudo ./voidgatectl status
Verify it works
The daemon starts in IDLE. status should show the interface you attached and a nonzero rx_pps once traffic flows. stats shows the raw XDP counters.
$ sudo ./voidgatectl status state=idle armed=0 rx_pps=412 rx_bps=2800000 prefixes=0 iface=eth0 $ sudo ./voidgatectl stats rx_pkts=18240 rx_bytes=12501440 passed=0 dropped=0 non_ip=0 map_full=0 parse_err=0 rx_pps=412 rx_bps=2800000 state=idle prefixes=0
In IDLE, passed stays at zero because the program does not parse packets. It only counts rx_* and returns XDP_PASS.
Attach mode
xdp_mode = auto tries native (XDP_FLAGS_DRV_MODE) then falls back to SKB. You can pin native or skb in the config. Tests do not require a vendor driver.
Run as a daemon
-d detaches into the background. The command waits for startup, then prints the daemon PID to stderr and exits 0. A startup failure exits nonzero. -s stop reads the pid file and stops the daemon, which detaches XDP on the way out.
sudo ./voidgate -d -c configs/voidgate.conf
sudo ./voidgate -s stop
- Logs go to stderr in the foreground, so under the systemd service to the journal (
journalctl -u voidgate), each line at its own priority. With-dthey go tolog_file(default/var/log/voidgate.log), append-only: after detaching, check there for startup diagnostics, and restart after rotating the file. - Pid file is
pid_file(default/run/voidgate.pid). The daemon holds a lock on it for its whole life, so a secondvoidgateexits withalready runningbefore it touches the NIC. - After a crash the kernel releases the lock, and the next start takes over the leftover socket and XDP program.
-s stoprefuses a stale pid file and never signals the pid inside it. -v/-vvraise verbosity. Relative config, log and pid paths resolve against the launch directory.
systemd
make install installs into the Seawall stack's prefix, /usr/local/seawall: sbin/voidgate, bin/voidgatectl, the default config in share/voidgate/voidgate.conf, libexec/voidgate-mkconf, the unit in /etc/systemd/system, and the OpenResty client in the stack's OpenResty. PREFIX, CONFDIR, LUA_DIR and DESTDIR change the locations; the unit runs /usr/local/seawall/sbin/voidgate whatever PREFIX is.
sudo make install
sudo systemctl enable --now voidgate
The unit runs the daemon in the foreground, without -d. Its config is /usr/local/seawall/etc/voidgate/voidgate.conf. On the first start voidgate-mkconf makes it from the default, with interface set to the one the default route goes out of, and never changes it after that: edit it there. make install, upgrades and make uninstall keep it.
[Unit]
Description=voidgate XDP DDoS gate
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
# "+": as root, before the capabilities below are dropped. Makes the
# config from the default on the first start, for this machine's
# interface.
ExecStartPre=+/usr/local/seawall/libexec/voidgate-mkconf
ExecStart=/usr/local/seawall/sbin/voidgate -c /usr/local/seawall/etc/voidgate/voidgate.conf
Restart=on-failure
RestartSec=2
AmbientCapabilities=CAP_BPF CAP_NET_ADMIN CAP_PERFMON
CapabilityBoundingSet=CAP_BPF CAP_NET_ADMIN CAP_PERFMON CAP_DAC_OVERRIDE CAP_CHOWN
LimitMEMLOCK=infinity
[Install]
WantedBy=multi-user.target
Layout
src/bpf/voidgate.bpf.c XDP program
src/bpf/voidgate.h shared map / packet structs
src/voidgate.c daemon
src/voidgatectl.c unix-socket client
lua/resty/voidgate.lua OpenResty control client
src/policy.c IDLE / ACTIVE policy
src/maps.c libbpf attach + LPM helpers
configs/voidgate.conf key=value
voidgate.service systemd unit
voidgate-mkconf makes the config on the first start
Generated, do not edit or commit: src/bpf/voidgate.skel.h, *.o, binaries.