Skip to content

building

Thomas Mangin edited this page Aug 17, 2026 · 10 revisions

Pre-Alpha. This page describes behavior that may change.

Building Ze from source is a single command if you have Go 1.26 and a working toolchain on the path. CGO is disabled globally. The Makefile is the source of truth for every build target, and make help lists them all grouped by category. This page is the short version.

Prerequisites

You need Go 1.26 or newer. The repo and the module path are both github.com/ze-software/ze.

go version    # 1.26 or newer
git clone https://github.com/ze-software/ze.git
cd ze

If you only want a ze binary and no checkout, go install works, but it needs the feature tags spelled out because they are off by default:

go install -tags 'ze_core ze_distro ze_anomaly ze_as112 ze_bfd ze_bgp ze_bmp ze_copp ze_cos ze_ddos ze_dhcpserver ze_exabgp ze_flowexport ze_geodns ze_gnmi ze_grpc ze_ike ze_isis ze_l2tp ze_ldp ze_lg ze_mcp ze_mpls ze_mrt ze_ntp ze_ospf ze_policyroute ze_pxe ze_radius ze_rest ze_rsvpte ze_ssh ze_tacacs ze_telemetry ze_trafficusage ze_vpp ze_vrrp ze_web' github.com/ze-software/ze/cmd/ze@latest

The shortest path

make build

That builds bin/ze (the daemon and CLI), bin/ze-test (the functional test driver), bin/ze-chaos (the chaos orchestrator), and bin/ze-analyse, and regenerates docs/comparison.html from the markdown source. bin/ze-perf is not included; build it separately with make ze-perf-build. The version is injected via ldflags from the current date in the form YY.MM.DD.

If you only want the daemon, the per-binary target is faster.

make ze-build        # bin/ze only
make ze-chaos-build     # bin/ze-chaos only
make ze-test-build      # bin/ze-test only
make analyse   # bin/ze-analyse only

Protocol buffer toolchain

Regenerating the gRPC API stubs requires protoc, protoc-gen-go, and protoc-gen-go-grpc on the PATH. These are only needed if you edit api/proto/*.proto; the committed generated Go files are enough for a normal build.

make ze-dev-setup      # Install protoc-gen-go and protoc-gen-go-grpc into $GOBIN

protoc itself is not a Go tool, so install it from your system package manager (brew install protobuf, apt install protobuf-compiler, etc.) or from the protocol buffers release page. After make ze-dev-setup finishes, make generate regenerates the proto stubs. See gRPC API for the resulting service surface.

Gokrazy VM appliance

make ze-gokrazy-deps-download and make ze-gokrazy-build build a bootable x86_64 VM image with Ze as its only application. The first target fetches the Linux kernel and gokrazy init packages into the Go module cache (one-time, ~42 MB). The second target cross-compiles Ze and assembles the image. make ze-gokrazy-run boots the result in QEMU for testing. The full appliance build walkthrough is on the appliance page.

Two kernel targets exist and they are not interchangeable. make ze-kernel-vmlinuz-stage KERNEL_ARCH=amd64 stops at tmp/kernel/vmlinuz, which is all the QEMU functional targets need, and it downloads no gokrazy module cache. make ze-kernel-build adds the out-of-tree gokrazy kernel package on top, and that half does need make ze-gokrazy-deps-download first. Both go through a durable cache under ~/.cache/ze, keyed on architecture and resolved config, so a second build with the same key materialises instead of spending about 30 minutes.

Build tags

Ze uses a unified binary with positive build tags to select personalities. The main binary (bin/ze) is built with the ze_core tag. Other binaries are build-tag variants of the same source:

Binary Build tag Purpose
bin/ze ze_core Daemon, CLI, SSH server.
bin/ze-test ze_test Functional test driver.
bin/ze-chaos ze_chaos Chaos testing orchestrator.
bin/ze-perf ze_perf Performance benchmark tool.
bin/ze-analyze ze_analyze MRT and RIB analysis tool.

Additional tags layer features on top:

Tag Purpose
ze_distro Linux distribution features (systemd, package management).
ze_appliance Appliance management commands.
ze_setup Build tooling and setup commands.
ze_stripped Minimal build with reduced feature set.
maprib Swaps the BART trie RIB for a Go map (benchmarking).
ZE_TAGS=maprib make ze-build

Feature gates

Beyond the personality tags above, Ze can compile whole subsystems out at build time. Each optional subsystem is guarded by a ze_<feature> build tag. Leaving the tag off drops that subsystem's code from the binary, for a smaller image and less attack surface. A build with a subsystem compiled out does not link it and rejects its config block as unknown.

The default-on set lives in one place, feature-gates.txt, and every consumer derives from it: the Makefile's ZE_FEATURES, the functional-test build tags, the plugin-import generator, the dependency audit, and the generated tag lists in .golangci.yml, gokrazy/ze/config.json and the quickstart go install line. Adding a gate is a one-line edit to that file plus make generate. make ze-build and make ze-appliance-build build with every default-on feature; make ze-stripped-build keeps only the SSH management plane and drops the rest; a bare go build -tags ze_core drops all of them.

Thirty-six subsystems gate today.

Management and API surfaces

Tag Subsystem
ze_ssh SSH server (the base operator management plane).
ze_web Web interface.
ze_lg Looking Glass.
ze_gnmi gNMI server.
ze_mcp MCP server.
ze_rest REST API transport.
ze_grpc gRPC API transport.
ze_telemetry Prometheus / telemetry exporter.

Routing protocols

Tag Subsystem
ze_bgp The BGP engine, codec, and every BGP plugin. The largest gate.
ze_bmp BMP receiver and sender. Requires ze_bgp.
ze_mrt MRT routing-information export. Independent of ze_bgp.
ze_ospf OSPF (v2 and v3).
ze_isis IS-IS.
ze_ldp LDP.
ze_rsvpte RSVP-TE.
ze_bfd BFD engine. The bfd/api client seam stays always-on.
ze_vrrp VRRP.
ze_mpls MPLS show-forwarding surface. Kernel MPLS forwarding stays on.
ze_exabgp ExaBGP compatibility bridge and the ze exabgp root command.

Subscriber, VPN, and dataplane

Tag Subsystem
ze_l2tp The BNG: L2TP LNS, PPPoE server and client, subscriber management.
ze_ike IKEv2 / IPsec control plane.
ze_radius RADIUS client and AAA backend.
ze_tacacs TACACS+ AAA backend.
ze_vpp VPP dataplane and every per-plugin VPP backend.
ze_cos Class-of-service profiles.
ze_copp Control-plane policing.
ze_policyroute Policy-routing engine.

Services and telemetry plugins

Tag Subsystem
ze_dhcpserver DHCP server.
ze_ntp NTP client.
ze_as112 AS112 reverse-DNS sink.
ze_geodns Geo-aware authoritative DNS.
ze_pxe Netboot pair: TFTP server plus HTTP image server.
ze_flowexport NetFlow v9, IPFIX, and sFlow export.
ze_trafficusage Per-host traffic accounting.
ze_anomaly Traffic anomaly detection and shaping response.
ze_ddos DDoS detection and mitigation responders.

Build a hardened, minimal daemon or add specific features on top:

make ze-stripped-build                                 # SSH only, all optional features dropped
go build -tags 'ze_core ze_ssh ze_web' ./cmd/ze  # SSH plus web only
go build -tags 'ze_core ze_ssh ze_ospf' ./cmd/ze # An OSPF-only router, no BGP

Gates compose independently where the code allows it. REST and gRPC gate separately, so a build can ship one transport without the other. Metric collection stays linked in every build; only the HTTP exporter is behind ze_telemetry, so a no-telemetry binary still records counters but cannot expose them over HTTP.

Two gates depend on another: ze_bmp needs ze_bgp because BMP monitors the BGP RIB, and the l2tp RADIUS auth plugin needs both ze_l2tp and ze_radius. ze_mrt is deliberately independent, and loads inert without a BGP source.

Some contracts stay always-on so a dropped feature degrades rather than breaks. bfd/api is a nil-able seam that BGP, OSPF, and static consume, and every consumer nil-checks it, so a BFD-less build runs those protocols unchanged. Kernel XFRM programming stays on for OSPF RFC 4552 authentication even without ze_ike. A config that selects a compiled-out subsystem is rejected as unknown rather than silently ignored, so ze_tacacs off means system { authentication { tacacs {} } } fails to load instead of falling through to another method.

Tests

The Makefile splits tests into a few targets so you can run only what you need.

Target What it runs
make ze-unit-test Go unit tests for everything except cmd/ze-chaos.
make ze-functional-test Functional tests against a built bin/ze.
make ze-fuzz-test All fuzz tests.
make ze-chaos-test The unit, functional, integration, and web chaos suites.
make ze-standard-test Lint, unit, functional, ExaBGP, and fuzz combined.
make ze-precommit-verify The full pre-commit check: lint, unit, functional, and ExaBGP.
make ze-ci-verify Lint, unit tests, and build.
make ze-precommit-verify-changed Run ze-precommit-verify only on packages touched in your branch.
make ze-repository-tracked-build-check Compile what git holds, not the working tree.

ze-precommit-verify is the one that must pass before you submit a patch. ze-ci-verify is a lighter target (lint, unit tests, and build) used in CI.

The tracked-build gate

Every other build and test target here compiles the WORKING TREE. A commit that lands a consumer while its producer stays uncommitted therefore passes every gate and breaks main for everyone else. On one day in August 2026 four commits did exactly that, each green at the moment it landed.

make ze-repository-tracked-build-check              # judge HEAD
make ze-repository-tracked-build-check REV=<sha>    # judge any past commit

It extracts the commit with git archive and compiles the extracted tree over six build-tag flavors. Each flavor names a tag-gated file its own tags must select, and the run counts the selected packages against a floor, because go build ./... exits 0 over a pattern that matched nothing buildable. A warm run is about 45 seconds.

The gate is detective rather than preventive: it judges what git already holds, so the commit that breaks HEAD is caught by the next run. _test.go files are outside it forever, because go build never compiles them.

Cadence targets

make ze-precommit-verify runs 28 stages and the nightly workflows run about a dozen more. The repository has more than forty check, census, and audit targets, so the set in neither list was run by nobody. Three targets collect that set by how often it is worth running.

Target Cost Members
make ze-cadence-daily-run seconds, no Docker and no verify lock ze-repository-check (gate), plus the STE writing check, the spec status report, the problem journal, and the ze-dev-setup probe
make ze-cadence-weekly-run minutes, local ze-consistency-check, ze-unit-reactor-test-race, ze-chaos-verify (gates), plus the rules-router report, the RFC extraction backlog, the vendored-web update check, and the test-health record
make ze-cadence-monthly-run needs Docker, QEMU, or root the deployment preflight, ze-qemu-integration-test, the performance gate, mutation testing on changed files, and the STE review

A member is a gate or a note. A gate has a verdict and its non-zero exit fails the run. A note is a census that exits 0 whatever it finds, so it is printed and never fails the run. Every member of ze-cadence-monthly-run is a note, because a machine without Docker or QEMU would otherwise learn only that the target always fails.

ze-cadence-weekly-run takes the same repository-wide lock as ze-precommit-verify, so do not start it beside a verify: it blocks rather than fails, which looks like a hang.

Test parallelism

The Makefile caps test parallelism at half the available cores so a make ze-precommit-verify does not pin every core on the box. If you want to override that, set GOMAXPROCS directly. The Go build cache lives at cache/go-cache inside the checkout, not in TMPDIR, because Unix socket tests can hit the path-length limit on /tmp. cache/ is a symlink to a durable location outside the tree, so wiping scratch does not cost you a full rebuild.

Go through make rather than calling go test directly. A bare go test drops the feature build tags, so it compiles a different binary from the one the suites run and can report a red that does not exist.

Build outputs

Everything that comes out of the build lands in bin/.

bin/ze            # daemon, CLI, and the SSH server
bin/ze-test       # functional test driver
bin/ze-chaos      # chaos orchestrator
bin/ze-analyse    # MRT and RIB analysis tool

Docker

make ze-docker-build                                        # Build ze:latest
make ze-docker-build ZE_DOCKER_IMAGE=myregistry/ze          # Custom image name
make ze-docker-build ZE_TAGS=maprib                          # With extra build tags
make ze-docker-lab-build                                    # Build netlab/ze:latest

There are two images. ze:latest is a static binary on a scratch base (119 MB) for deployments. netlab/ze:latest is an Alpine base with tini and iproute2 (137 MB) for labs under netlab and containerlab. Both derive their feature tags from feature-gates.txt, and ZE_TAGS adds to that set rather than replacing it. See Docker for the full guide and netlab for the lab image.

Other useful targets

make help                 # The full list of targets, grouped by category
make generate             # Regenerate plugin imports
make ze-lint              # Run the linter pass
make ze-perf-build              # Build `bin/ze-perf`. Run benchmarks with `make ze-perf-bench`
make ze-spec-status       # Spec status report
make ze-command-list      # Generated command list
make ze-doc-drift-check         # Detect docs that have drifted from the code

See also

Adapted from main/Makefile and main/CONTRIBUTING.md.

Home

About

First Steps

Configuration

Operation

Interfaces

Plugins

Plugin Development

Chaos Testing

Blueprints

Development

Reference

Clone this wiki locally