Changes
What shipped in Ze, newest first. This is a condensed changelog mined from the same weekly updates as the blog; each entry links to the full write-up. Ze is pre-release, so the configuration syntax can still change: anything that affects an existing config is called out in the week it lands, and the roadmap tracks the path to a stable release.
Week of 2026-06-25
Shipped across security, the appliance, routing, and observability this week.
- Control-plane survival: A big push to keep the control plane alive under attack:; GTSM / TTL-security (RFC 5082) for BGP; CoPP policing on TCP/179; Egress CS6 scheduling; On-demand flowspec route origination with a tag registry; Automatic DDoS detection and auto-mitigation, with a Flowtriq reporter, attack-target prefixes pulled from live traffic stats, and attack characterization feeding a surgical responder
- Feature gates: Ze can now compile subsystems out at build time: gNMI, MCP, REST/gRPC APIs, the Prometheus exporter, and each of ISIS / LDP / OSPF / RSVP-TE. Smaller images, less attack surface.
- Appliance & installer: The installer's old busybox shell initrd is gone, replaced by a single pure-Go PID-1 binary that boots the same way over PXE or off USB/ISO media. Along with it: boot-NIC pinning, DHCP recovery, MAC-pinned recovery, a gated rescue shell, SSH enabled on the appliance, and consolidated build outputs with faster incremental kernel builds.
- Routing & access: Per-family import/export filtering with an egress gate; Fixed an AS_PATH rewrite panic; L2TP dead-peer detection and route withdrawal on teardown; PPP now keeps IPv4 up when IPv6CP is declined; Leaner ISIS/OSPF hot paths
- Observability: New GeoDNS per-source-IP server plugin; Lazy traffic-stat aggregation and a multi-subscriber observation feed
- Under the hood: Storage now self-heals a corrupt blob store on open, the internal module layout got tidied up, and there's a unified dev bootstrap.
- Coming up: Design work started on AS112 anycast DNS and kernel lockdown / hardening.
Week of 2026-06-22
Focused on trimming attack surface and rounding out OSPF.
- Feature gates: SSH and Looking Glass can now be compiled out at build time, continuing the work toward smaller images with less attack surface for deployments that don't need them.
- Routing: A unified OSPFv2/OSPFv3 engine, with IPv6 interop coverage; BGP redistribution now has a dedicated producer exporting RIB best-paths; Live SSE views for OSPF and IS-IS state in the web UI
- Observability: eBPF-based per-port, per-IP traffic accounting (TCX), validated against the runtime kernel.
- Under the hood: A Fintek Super-IO serial console fix for Alder Lake-N hardware, and the installer now probes for a reachable install server before trusting the default route.
Week of 2026-06-15
Native IS-IS landed, MPLS gained fast reroute, and firewall rules can now pull straight from the IRR.
- IS-IS & MPLS: A native IS-IS link-state IGP (ISO/IEC 10589, RFC 1195/5305/5308/5301/5303/5304/5310/2966): full PDU/TLV codec, adjacency FSM for point-to-point and LAN, LSDB flooding, DIS election, SPF with ECMP install into the Loc-RIB, HMAC auth, and dual-stack IPv6, interop-tested against FRR's isisd. Interface config now nests under
interfaces { }, matching OSPF's convention.; RSVP-TE fast reroute (RFC 4090 facility backup): a Point of Local Repair redirects a protected LSP onto a pre-armed bypass on link failure without tearing down the LSP, and tunnels reconcile correctly across a config reload.; BGP-LU labeled unicast now has a full label path through the kernel FIB, LDP, and RSVP-TE. - BGP: SR-Policy routes: decode, JSON output, and CLI
--nlri decodesupport; A pass fixing eight RFC 9252 compliance bugs in SRv6 Prefix-SID, found during external review (wire-format field sizes, TLV bounds checks, SID length validation); Per-family ADD-PATH mode enforcement, plus a new PATHS-LIMIT capability (draft-abraitis-idr-addpath-paths-limit) with add-path config unified into a single block; FlowSpec rate-limit now accepts an explicit:bytesunit (RFC 8955), and the ExaBGP-compatibility bridge moved to version 6.0.0 to match ExaBGP's own unified rate-limit syntax; A route-server race that could send duplicate or misordered End-of-RIB markers on reconnect is fixed - Firewall / IRR: A new firewall plugin resolves ASN and AS-SET references against the Internet Routing Registry and turns them into nftables prefix-list filters automatically, with dual-stack support, per-interface source validation, and commit-time verification that rejects any reference that hasn't been cached yet.
- Interfaces: Interfaces can now bind to the underlying kernel device by hardware MAC address instead of by OS-assigned name, so the binding survives a NIC rename or a MAC override.
show interfacealso now exposes the permanent factory MAC and OS device name. - CLI: Running
zewith no arguments now opens a hierarchical TUI menu of every command, with type-ahead filtering and drill-down into sub-commands. Environment-key values now autocomplete in both the operational CLI and the shell, and help output is consistently colored across every surface. - Appliance & provisioning: Provisioning now logs per-request detail (DHCP lease, TFTP read, served image identity) at a visible level by default, so a PXE boot sequence isn't silent, and an installed appliance can report which build it's running via
ze version. PXE-provisioned interfaces get their address auto-configured. The runtime kernel picked up fixes for L2TP support on kernel 7.0 and for the serial console driver, and the installer now shows console output on headless serial hardware and recovers from a foreign DHCP lease that has no route back to the install server.
Week of 2026-06-08
A week of operator-facing polish: a real Web Workbench UI, SR-Policy and IRR-based filtering in BGP, per-subscriber CoS, and a talk at LINX.
- BGP: SR-Policy NLRI (SAFI 73) and Tunnel Encap decode, with an ExaBGP bridge; IRR-based prefix filtering, with ASN fallback and a configurable PeeringDB URL; The ATTR_TOMBSTONE mechanism (see the
draft-mangin-idr-attr-tombstone-00; write-up from a few weeks back) now also covers ASN transcoding: a; malformed AGGREGATOR hit while rewriting between 2-byte and 4-byte ASN; encodings gets tombstoned in place instead of forwarding corrupt bytes; downstream - Web Workbench: The web UI is now the default operator surface (the old bottom CLI bar is gone):; Live BGP summary and a streaming log view; Real health status and system resource reporting; Peer detail, navigation, and Add Peer form fixes
- CLI: 21 plugin commands renamed for consistency, with autocomplete driven straight from the command registry. A new
ze formatcommand formats config for offline pipelines. - Class of Service: Dynamic per-subscriber CoS driven by RADIUS, including vendor-specific attribute extraction, plus VLAN 802.1p QoS maps on both the kernel and VPP paths.
- Installer: Ventoy compatibility for ISO installs, server-reachability diagnostics before accepting a PXE lease, and faster kernel builds (multi-threaded, cached).
- Under the hood: Ping now uses an internal ICMP engine instead of shelling out to the OS
pingbinary, and there's a liveshow debugRPC for inspecting daemon state. - Presentation: LINX 126: Presented "From ExaBGP to a Network OS with AI" at LINX 126 this week,; covering the move from a BGP daemon to a full network OS. Glad to have had; the chance to bring that to the LINX community in person.
Week of 2026-06-01
The CLI grammar rollout finished, MRT tooling arrived, and a handful of quiet-but-important reliability bugs got fixed.
- CLI: The verb-first, show-a-noun command grammar reached the rest of the command surface this week: interfaces, process lifecycle, cache, log, metrics, MPLS, DNS, traffic/QoS, IKE, traceroute, ping, monitor, and BGP peer/cache/commit commands all follow the same pattern now. Bare list/summary commands without an explicit verb are gone. Interface commands also got smarter: creating a sub-interface auto-creates its parent, and the MAC address setting moved under a
mac { }container. - MRT tooling: Ze can now record, replay, and analyze BGP sessions in MRT format (RFC 6396/6397/8050), the standard used by RouteViews and RIPE RIS:; A daemon component recording three independent dump streams with time-based file rotation; RIB dumps (TABLE_DUMP_V2) and BGP4MP UPDATE recording; Analysis tools: statistics, filtering by peer/prefix/timestamp/type, AS-path/community regex, inject, replay at configurable speed, and conversion to pcap or JSON; A standalone offline BGP message decoder with
bgpdump-style human-readable output; MRT files servable over HTTP, and aze-chaos --mrt-fileflag for recording chaos-test sessions - Appliance & installer: The installer kernel now builds from a base config plus a profile (qemu or hardware), with a
--profileoverride and PXE boot args tuned per architecture. ISO images gained a framebuffer console line for physical hardware with a monitor, plus gzip compression to shrink the image. - Reliability fixes: BMP now defaults to monitor-only, matching its role as a passive monitoring protocol (RFC 7854); it no longer injects received routes by default; RPKI's validation gate now skips cleanly when no RTR cache servers are configured, instead of leaving every route waiting 30 seconds for a validation response that will never arrive; L2TP tunnel IDs are now seeded from the listener port, so multiple ze instances (or parallel test runs) no longer collide on tunnel ID 1; a stale tunnel left behind by a crash is now detected and cleaned up automatically; Config reload now falls through correctly to a newly-added peer's embedded config instead of erroring; PKI certificates now load correctly during hub reload, not just at startup
- Config validation: Required-field enforcement, previously BGP-specific, is now generic: any YANG list can mark fields required and have them checked on
ze config validateand in the editor, currently applied to VPN, PKI, and L2TP sections.
Week of 2026-05-25
MPLS grew a full label-switching stack, flow export and gNMI landed, and config commits became transactional.
- MPLS: Label switching across three layers, verified live in QEMU against FRR:; Kernel MPLS dataplane: push, swap, and pop programmed via netlink, with relabel support that updates a route ze already owns without clobbering another writer's; LDP (RFC 5036): per-interface Hello discovery, a TCP session FSM, a label information base, and downstream-unsolicited distribution; RSVP-TE with FRR interop; Per-interface MPLS input and MPLS sysctl keys on interfaces
- Observability & telemetry: Flow export: sFlow v5, NetFlow v9 (RFC 3954), and IPFIX (RFC 7011), with per-flow records and interface counter export to external collectors; A new gNMI component (Capabilities, Get, Set, Subscribe over gRPC) for YANG-modeled config management;
show bgp peeroutput enriched to NOS-grade detail, and all IANA well-known BGP community names are now recognised;ze supportgenerates a tech-support bundle, and SMART disk health reporting moved to a pure-Go ioctl reader (no more shelling out to smartctl);ze doctorpicked up more readiness checks: BGP MD5 support detection, VPP socket path validation, NTP/RPKI/BMP checks, and a semantic validation bridge - CLI: All plugin-owned commands were renamed to a consistent verb-first grammar. Command arguments are now declared as typed YANG leaves, driving completion, validation, and docs from one source. Other additions:
ze help commandfor a self-documenting command catalog,| first Nand| last Npipe operators, session transcript recording (so a crash or dropped SSH session still leaves a local record), a configurable default output format, and ANSI color support in the terminal buffer library. - Config & commit reliability: Config commits are now transactional: changes go through candidate/active/rollback versions and are only promoted after a runtime reload actually succeeds, with automatic cleanup of failed candidates. A new operation-graph solver orders config changes correctly across components (so, for example, an address and the peer that depends on it apply in the right sequence). Config schemas now carry a release-based stamp with an evolution framework for future migrations, and YANG
type emptyleaves can be used as simple presence flags. Separately, a real auth bug was fixed: PXE and bootstrap-provisioned appliances were never loading the zefs "power user," which silently broke SSH login and the web/API per-user auth path on freshly provisioned boxes. - BGP policy & RIB efficiency: New policy actions: an AS-PATH-length filter, increment/decrement on numeric attributes (local-preference, MED, AIGP), community add/remove, and an RFC 6996 remove-private-as filter. Policy chains can now use plain, operator-facing filter names instead of
<plugin>:<filter>refs, andshow policy testruns a chain against a supplied UPDATE without touching live state. On the RIB side, peer reconnect replay andbgp rib clear outnow use cursor-based grouped resend instead of per-route sends, cutting reconnect replay time on large tables from seconds to roughly 100-200ms. - Appliance & provisioning: PXE boot option support (RFC 4578) rounds out last week's DHCP/TFTP/image-server work. A busybox-based initrd now handles bare-metal PXE installs end to end (fetch, verify, write, reboot), and a first-boot bootstrap mode brings up DHCP and SSH automatically when a box has zefs but no config yet. Elsewhere: OTA image push via a vendored gokrazy updater, a unified update backend with platform-aware dispatch, and
ze servicefor installing Ze as a systemd service on standard (non-gokrazy) Linux hosts.
Week of 2026-05-18
A full native IPsec/IKEv2 VPN stack, a route server for IXPs, and a big allocation-hunting pass across the BGP hot path.
- IPsec / IKEv2 VPN: Ze gained a native IKEv2 implementation built from the wire format up, interop-tested against strongSwan:; IKEv2 crypto primitives and wire codec, with an FSM-driven engine handling auth, transport, and reconciliation; Child SA negotiation, dead-peer detection, rekeying, and a dataplane abstraction; EAP authentication (MSCHAPv2 and TLS), NAT-T, and a virtual IP address pool for remote-access clients; Route-based VPN via a new XFRM interface type; A PKI certificate store shared with TLS, with health checks and Prometheus metrics for certificate expiry; CLI, web UI, health checks, and metrics for managing tunnels end to end
- Routing, BGP & subscriber access: SRv6 Prefix-SID support (RFC 9252, RFC 8669); Recursive next-hop resolution, ECMP path grouping, and IGP-cost-aware best-path selection, feeding richer route attributes (type, metric, table, MPLS) into both the kernel and VPP FIB backends; A route server mode for IXPs: dynamic peer groups that accept sessions from any address in a configured range, RS-client transparent AS-PATH forwarding, and community-based selective forwarding (announce-only, do-not-announce, RFC 7999 blackhole); AIGP attribute support (RFC 7311); PPPoE and L2TP subscriber sessions now share one session model, making PPPoE visible to the same auth, address-pool, shaping, and telemetry plugins L2TP already had; BGP FlowSpec routes (RFC 8955/8956) can now drive local firewall rules directly; RPKI ASPA verification, shipped opt-in last week, can now enforce a reject policy on invalid AS_PATHs (log-only by default; a route that is ROA-valid but ASPA-invalid is still rejected)
- CLI & diagnostics: A pure-Go packet capture command (
show capture interface), an AF_PACKET-based tcpdump replacement for gokrazy appliances; An mtr-stylemonitor traceroutewith parallel per-hop probing, ECMP path awareness, and pipe support;monitor ping,monitor system(live netlink event streaming), and nine other diagnostic commands built in for gokrazy boxes; New pipe operators:| originfor ASN lookups and| resolvefor reverse DNS, usable from traceroute and ping output; CLI modes renamed to match standard NOS terminology:configureenters config mode,exitreturns to operational mode instead of quitting;ze start --clilaunches an interactive CLI attached to the daemon in one step; Machine-readable diagnostics for scripted or AI-assisted operations:ze explain <code>,ze config validate --json,ze help --ai --json - Appliance, provisioning & readiness:
ze installrestructured intolocalandremotesubcommands, plus a newze uninstall; Zero-touch provisioning: PXE boot extensions on the DHCP server, a TFTP server, and an HTTP image server, all shipped as ordinary Ze plugins; Self-update for thezebinary;ze doctorgained config-driven readiness checks across the board (disk space, DNS resolver, interfaces, SSH/API listeners, web TLS, kernel modules) and a--jsonmode for scripted prerequisite checks before starting the daemon; Config reload no longer drops connections: graceful, bind-before-close listener migration now covers the looking glass, REST, gRPC, and MCP servers, not just the web UI; Config files now carry a schema stamp; if a config becomes incompatible after a downgrade, ze recovers automatically from the rollback history - Performance: A focused pass on BGP's hot path: attributes are parsed once per UPDATE instead of once per NLRI, AS-PATH prepend and hold-timer resets are allocation-free on the fast path, JSON formatting for monitors and RIB output skips work when nothing is watching, and GC pressure across the reactor and event pipeline dropped significantly.
- Under the hood: ZeFS, Ze's internal storage layer, gained per-record CRC32c checksums, in-place writes, and a check/repair CLI. Remote fleet management got easier with per-service SSH credential storage and a
ze remoteCLI for targeting other instances. DNS resolver cache management (list, selective delete, flush, stats reset), firewall masquerade port mapping, additional conntrack helpers (NFS, SQL*Net), and per-interface rate tracking (CLI, Prometheus, web) also landed.
Week of 2026-05-11
CPE features round out, interface config gets restructured, and RPKI gains ASPA path verification.
- CPE / edge router: Several pieces needed for Ze to run as a customer-premises router landed together:; A DHCP server plugin (RFC 2131/2132) with lease tracking, static MAC-to-IP mappings, and multi-subnet dispatch; A PPPoE client interface kind, dialling an access concentrator and negotiating LCP/CHAP/PAP/IPCP for a routable PPP session; Declarative conntrack management (helper modules, table sizing, per-protocol timeouts); Serial console configuration for headless boxes, working on both gokrazy and standard Linux; A firmware update checker plus a
ze update-servecommand for hosting update manifests and binaries - Interfaces: Interface config got more structured: rp-filter's integer setting is now a
strict/loose/disableenum, addresses moved into per-familyipv4/ipv6containers (Junos/Nokia-style), interface units are now named by string label instead of numeric ID, and per-interface offload/steering (GRO, GSO, TSO, LRO, RPS, RFS, hw-tc-offload) is configurable. - Routing: Static routes gained named routing tables for policy-based routing, plus interface-only next-hops for point-to-point links; Kernel-installed routes (from DHCP, PPP, or manual
ip route add) can now redistribute into BGP; Connected prefixes and L2TP RADIUS framed routes redistribute the same way; Redistribution rules can now scope by destination protocol; BGP keepalive timer is configurable independently of hold-time; MPLS labels from BGP labeled unicast now flow through the RIB into the VPP FIB; A newbgp rib rpfcommand does LPM-based reverse-path lookups for external multicast daemons - Security: RPKI gained ASPA path verification against RFC 9582 provider authorization records over RTR v2. It ships opt-in, off by default, after an initial default-on release flagged every route as "unknown" wherever no ASPA infrastructure was deployed.
- Observability: BMP-received routes now live in their own RIB slot and show up in the looking glass under a dedicated "BMP Monitored Peers" section, kept separate from BGP best-path selection. Host hardware (CPU, NIC, memory, storage, thermal) is now live in the web UI, storage inventory picks up SMART health data, and a new hardware tuning engine (CPU governor, IRQ affinity, ethtool ring buffers) applies at startup and on config reload. NIC flaps, ECC error growth, and CPU throttling now surface in
show warnings/show errors. - Under the hood: Config archiving was redesigned around named blocks with triggers (commit, manual, daily, hourly) and change detection, and config history/rollback got a proper date-based version API. RIB attribute storage was reworked for better cache density, alongside a broader pass removing allocations from BGP's hot paths. The MCP server picked up the latest protocol additions: embedded UI resources and background task-augmented tool calls.
Week of 2026-05-04
Two major subsystems landed this week: a fleet management tool for appliances, and a PPPoE access concentrator alongside VPP-backed NAT and ACLs.
- Appliance fleet management: A new
ze appliancetool manages appliance images end to end.; Interactive or config-file init, with encrypted secrets (Argon2id + ChaCha20), bcrypt passwords, self-signed TLS certificates, and SSH key provisioning; Build, list, show, and day-2 operations: password change, certificate replacement, rekey, clone; Remote operations (push, config, batch init) and export/import for disaster recovery from a bastion host; Device-side config loading now validates before applying, and auto-reverts on failure; Appliance images now build for both amd64 and arm64 (useful for running under QEMU on Apple Silicon) - Broadband access (BNG): New PPPoE access concentrator (RFC 2516): discovery, anti-DoS cookies, per-interface session tables, and rate limiting; IPv6 wired into the PPP session lifecycle: prefix pools, DHCPv6-PD, and Router Advertisement building; RADIUS accounting now reports real traffic counters, and Access-Accept attributes are consumed to configure sessions; A string of Linux kernel-integration fixes were needed to get real PPP data flowing over L2TP: a missing kernel config option was silently disabling the L2TP Netlink module, tunnel sockets weren't connected to their peer (so transmission failed silently), and LCP's first request needed a retransmit timer since pppd wasn't ready to receive it yet
- Firewall & VPP dataplane: The VPP backend gained a classify pipeline (mark/limit actions), NAT44 (SNAT, DNAT, masquerade), and an ACL backend, and was hardened against failure patterns found during VyOS interoperability testing.
- Diagnostics: Per-session traffic diagnostics, VPP packet tracing, and pcap export.
Week of 2026-04-27
Interface configuration now rolls back cleanly on failure, the web UI got a dedicated CLI page, and traffic-control state survives more edge cases.
- Interfaces & routing: Interface configuration apply is now transactional: if any step (address changes, bridge ports, STP, mirrors, MTU, MAC, VLANs, tunnels) fails partway through, everything already applied gets rolled back instead of leaving a half-configured interface. Sysrib now accepts withdrawal batches that don't carry a specific protocol source, needed for a clean full Loc-RIB teardown, and HTB traffic shaping now uses correct kernel defaults.
- Web UI: The bottom CLI bar was replaced with a dedicated
/clipage that matches the SSH CLI layout, with the same tab completion, history, and prompt behavior. Workbench, Finder, and CLI are all switchable at runtime from the top bar, with the choice remembered, and login now redirects back to the page you originally requested. - Traffic control & telemetry: The netlink traffic-control backend now snapshots and restores the original qdisc instead of leaving it permanently replaced. Prometheus telemetry config was restructured: OS collector settings moved into their own container, HTTP Basic Auth is now available for the metrics endpoint, and a timing side-channel in the auth check was closed.
- Under the hood: REST/gRPC API streaming endpoints are now fully wired end to end, with authorization, accounting, and panic recovery. FIB startup no longer clobbers routes owned by static routing. L2TP route redistribution now emits real add/remove events instead of a stub.
Week of 2026-04-20
Security hardening, a new diagnostics subsystem, and a redesigned operator web UI headline this week.
- Security & hardening: SSH client connections now reject unknown remote hosts by default (insecure mode is opt-in), and managed-mode TLS verification is on by default; Security headers (CSP, HSTS, clickjacking protection) now also apply to failed-login and unauthenticated responses, not just logged-in pages; Per-user SSH public key authentication; BGP correctness fixes: the OTC treat-as-withdraw path is now bounds-checked, best-path selection falls back to router ID when ORIGINATOR_ID is absent, and export filters no longer share mutable state across peers; BFD detection timing now correctly follows RFC 5880's RemoteDesiredMinTx
- Observability & diagnostics: A new diagnostics subsystem shipped: structured log queries, a component health registry with a
/healthendpoint, packet capture rings for L2TP and BGP, active ping/route-lookup probes, and FSM history for BGP peers and L2TP tunnels/sessions. Netdata-compatible telemetry collectors now cover memory, disk, CPU, network, IPv6, and ZFS/btrfs/mdstat, each independently configurable. - Web UI: A new RouterOS-style "workbench" operator UI landed behind a feature flag, with two-level navigation and per-domain dashboards. Embedded services (gokrazy console, L2TP, health) now render inside a portal iframe instead of separate tabs.
- Routing: New policy-based routing plugin with next-hop actions; New static route plugin: ECMP, weighted next-hops, BFD-triggered failover, and a VPP backend with redistribution
- Route-server performance: Route-server forwarding now bypasses the plugin dispatch chain for a reactor-native fast path, with batched withdrawals and deferred flush. The event hot path switched from string keys to typed integer IDs, and the Loc-RIB is now sharded by prefix hash to cut lock contention.
- Under the hood: MCP gained elicitation (interactive prompts mid tool-call) and OAuth 2.1 remote binding. A new
tcp-mss-setfirewall action clamps TCP MSS. Static DNS name servers are now configurable, with resolver config unified.
Week of 2026-04-13
A complete L2TP/PPP access stack, TACACS+ and pluggable AAA, a VPP dataplane, and new nftables/tc firewall backends.
- L2TP & PPP access: Ze gained a full L2TPv2 implementation for broadband access.; Wire layer, tunnel FSM (SCCRQ/SCCRP/SCCCN handshake with tie-breaker resolution), and session FSM (ICRQ/ICRP/ICCN, OCRQ/OCRP, CDN); Reliable delivery engine (sequencing, congestion window, reordering) and HELLO keepalives; PPP authentication: PAP, CHAP-MD5, and MS-CHAPv2, with LCP auth-protocol fallback and periodic CHAP re-authentication; Wired into config reload, the CLI, and route redistribution
- Authentication & AAA: TACACS+ client wired into SSH, web, and API authentication, behind a new pluggable AAA backend registry; Multi-user YANG-based login,
ze passwd, and Junos-style plaintext password import - Firewall, traffic control & VPP: New nftables firewall backend and tc-netlink traffic-control backend, sharing one YANG data model, plus
show firewall/show traffic-controlCLI commands; VPP dataplane support: connection management, startup.conf generation, DPDK binding, FIB programming via GoVPP, and a VPP interface backend with MAC/monitor support; VPP-backed traffic control now rejects unsupported configuration at commit time instead of failing later - Interfaces & sysctl: IPv6 default routes are now managed from Router Advertisements; DHCP-installed routes can carry a configurable priority (route metric), for multi-uplink setups; Named sysctl profiles for interface units, with an offline
ze sysctlCLI and three-layer precedence - Route-server performance: Route-server forwarding got a fast path: a reactor-owned forwarding cache cuts allocations on the per-UPDATE hot path. RIB best-path records are packed more tightly with a shared interner, next-hops now store as typed IP addresses instead of strings, and encoding for FlowSpec/BGP-LS JSON and static/MVPN UPDATEs got zero- or low-allocation paths.
- Under the hood: New
show host *commands surface hardware inventory. MCP now speaks Streamable HTTP transport with session management. The gokrazy appliance boots its config entirely from zefs (no static files), with first-boot bootstrap merging a template with live interface discovery, and a management proxy now exposes gokrazy's own console through Ze's web server. BFD authentication state now survives a session restart. BMP Route Monitoring was silently sending collectors headerless, malformed messages; it now emits complete RFC 4271 BGP messages. Redistribution can now filter per source family.
Week of 2026-04-06
A full BFD engine, BGP route reflection and policy filters, a real REST/gRPC config editor, WireGuard support, and a talk at Net Manchester.
- BFD liveness detection: A complete BFD implementation shipped end to end:; Transport hardening (GTSM, jitter, single-hop and multi-hop per RFC 5881/5883); BGP peer opt-in, so a session can require BFD before it's considered up; Authentication (RFC 5880 keyed SHA1/MD5); Echo mode; Operator visibility: show commands and Prometheus metrics
- BGP routing and policy: BMP (RFC 7854): wire format, receiver, sender, and Adj-RIB-Out support (RFC 8671); Route reflection (RFC 4456), next-hop control, and multipath; A new policy filter chain: prefix-list, AS-path regex, community match, and route attribute modification (local-preference, MED, AS-path prepend); The first piece of a broader policy framework, including loop-detection filtering; N-way best-path selection with a
rib show bestreason trace - Config editor and API: A real REST and gRPC API landed on top of a shared transport engine, with TLS, a Swagger UI, and a working config editor with per-user auth.
- Interfaces: WireGuard support: configure, reconcile, and tear down interfaces; GRE, IPIP, SIT, and IP6TNL tunnel interfaces; DHCP client wiring for routes, DNS, and NTP discovery on every ethernet interface; An NTP client plugin for system clock sync
- Appliance: A gokrazy VM appliance build for x86_64.
- Presentation: Net Manchester: Presented "Ze: Redoing and improving on ExaBGP" at Net Manchester this week,; walking through why Ze exists and what it does differently from ExaBGP. Good; session, and a good crowd to have that conversation with in person.
Week of 2026-03-30
A full interface management subsystem, offline DNS/RIR resolution tooling, config-driven plugin loading, BGP healthcheck and long-lived graceful restart support, and a Looking Glass overhaul.
- Interfaces: A new interface management subsystem landed with a JunOS-style unit model.; Netlink-backed interface monitoring, with
ze show interfaceandze interface migrateover SSH; DHCP client, SLAAC, and migration between backends; MAC discovery with descriptive interface naming; Per-interface sysctl settings and traffic mirroring applied straight from config; A declarative config apply/reload pipeline, with admin distance now wired into route selection - DNS & resolution: New offline
ze resolvecommand for DNS, Team Cymru ASN lookups, PeeringDB, and IRR queries, with 1-hour caching for the PeeringDB/IRR lookups; DNS queries now advertise a 4096-byte EDNS0 buffer, and truncated responses log a warning instead of failing silently - Config-driven plugins: BGP can now be loaded and unloaded at config reload time without restarting Ze, with plugin startup ordered by a dependency chain; Plugins in general can be dynamically loaded and unloaded on reload; The config editor now inlines single-child containers for display (
remote ip 192.0.2.1instead ofremote { ip 192.0.2.1 }) and flags missing required or suggested fields - CLI & Looking Glass: One-shot commands via
ze -c(replacing--run); Structured, colored help across all commands, with dispatch-key discoverability; Newrib inject/rib withdrawcommands for direct RIB manipulation, and a text-mode AS-path graph terminal forrib show best; Looking Glass overhaul: prefix summaries, downloads, dark mode, a next-hop graph view, and a help tab - Routing: New BGP healthcheck plugin: monitors service availability via shell probes and drives route announce/withdraw (or a MED override) through watchdog groups; Long-lived graceful restart (RFC 9494): stale routes are now correctly filtered or withdrawn per peer on egress, based on each peer's LLGR capability; New FIB pipeline installs best-path routes from protocol RIBs into the kernel via netlink (a P4 backend is stubbed in); Fixed a VPN next-hop encoding bug where the route-distinguisher slot could carry stale bytes left over from a previous UPDATE instead of the RFC 4364-required zero padding
- Under the hood: Forwarding to peers now defaults to zero-copy, only copying a buffer when an egress filter needs to modify the payload; the forwarding pool also auto-sizes per peer based on burst size instead of using fixed global pools. HTTP responses now carry an
X-Ze-Versionheader.
Week of 2026-03-23
A full web interface, fleet management, redistribution filtering, and a stack of routing-protocol correctness work all landed together.
- Web interface: A browser-based config editor shipped alongside the existing CLI and SSH editor:; YANG-driven rendering with per-user drafts, inline diffs, and live SSE updates; Admin commands, finder-style navigation, and a light/dark theme toggle; Started with
ze start --web; Hardened against DoS, SSE injection, and XSS (capped request bodies, tightened CSP, sanitized SSE event types); The web server now refuses to start without blob storage backing it, so TLS keys can't leak to the filesystem - Fleet management: A managed/fleet-config system landed: named hub blocks with per-client authentication, a managed client with first-boot TLS bootstrap, duplicate-client rejection, and CLI flags for managed mode. A client stops itself automatically if
managedis turned off in its config. - Redistribution filtering: External plugins can now filter and modify routes on ingress and egress: a YANG-configured filter chain with piped transforms and reject short-circuit, wired into the reactor's forwarding path, shipped with a working community filter plugin.
- Plugin and session security: Plugin TLS hardened with per-plugin tokens, certificate pinning, and secret clearing from the environment; The ExaBGP compatibility bridge gained a TLS connect-back mode for engine-launched plugins; A new plugin debug shell inspects a running plugin over an SSH channel; Two new subsystems: a cached DNS resolver component (used by decorators such as Team Cymru lookups), and an MCP server exposing six tools for AI-assisted BGP operations (announce, withdraw, peers, peer control, execute, commands)
- Routing correctness: Route loop detection: AS-path, ORIGINATOR_ID, and CLUSTER_LIST loops are caught and silently withdrawn before reaching prefix limits or plugins (RFC 4271 Β§9, RFC 4456 Β§8); Hold timer split in two per RFC 9687:
receive-hold-time(the classic RFC 4271 timer) andsend-hold-time(auto by default); Fixed peers configured with only a per-peer local-as sending AS_PATH with ASN 0, which other implementations correctly reject under RFC 7607; Graceful TCP close now drains before closing, so a pending NOTIFICATION can't be lost to an RST; Junos-styleinactive/deactivateconfig: mark any config block inactive without deleting it, with matchingshow | active/show | inactivefilters; Update groups now build one UPDATE per group of peers sharing identical attributes instead of one per peer - Observability and prefix hygiene: Prometheus instrumentation expanded with histograms, session lifecycle, wire metrics, and plugin health (status, restarts, delivery); New prefix data infrastructure pulls maximum-prefix guidance from PeeringDB and IRR/RIR delegation data, tracks staleness, and warns on stale data at login and in
show; Forward-pool congestion handling gained weight-based auto-sizing and two-threshold backpressure: soft buffer denial for the worst-offending peer, then forced GR-aware session teardown if a peer keeps hogging the pool - Performance and benchmarking: TCP_NODELAY is now enabled on production BGP sessions, and outgoing packets get DSCP CS6 marking. The
ze-perfbenchmarking tool grew report generation and gained more implementations to compare against: RustyBGP, freeRtr, and GoBGP alongside BIRD.
Week of 2026-03-16
RPKI route origin validation landed in full, alongside a wave of BGP RFC compliance work, CLI polish, and daemon security hardening.
- RPKI route origin validation: A complete RPKI pipeline shipped this week:; A new plugin speaks the RTR protocol, maintains a ROA cache, and validates route origins against it; A decorator plugin merges validation state into update events for downstream consumers; Validation now gates the adjacency RIB-in ingest path, so origin state is known as routes arrive, not after the fact
- Routing & RFC compliance: RFC 9234 Only-to-Customer (OTC) attribute processing, enforcing customer/peer/provider role safety; RFC 9494 Long-Lived Graceful Restart, extending stale-route retention beyond the standard GR timer; RFC 8203 Administrative Shutdown Communication, so peers get a reason string on planned shutdown; A GR restart marker for detecting a Restarting Speaker (RFC 4724); Enhanced Route Refresh BoRR/EoRR markers (RFC 7313); A fix for RFC 9072 extended optional parameter detection in OPEN parsing; BGP-LS attribute type 29 decode/encode, covering 40 TLV types; Per-peer, per-family prefix limit enforcement (RFC 4486); Peer configuration moved from template inheritance to Junos-style peer-groups
- Route delivery reliability: Adj-RIB-in now replays known routes to a peer as soon as it reaches Established, so new or reconnecting peers don't wait on fresh updates to converge. Outbound forwarding is also non-blocking now: a bounded per-peer overflow buffer and write deadline mean one slow or stuck peer can no longer stall delivery to everyone else, with peer-congested/peer-resumed events exposed to plugins.
- CLI & operator experience: New
bgp monitorcommand streams live BGP events;ze config ls,cat,import, andrenameround out config file management; Peers can be selected by ASN (as<N>) with completion support; Nushell shell completion joins the existing bash/zsh/fish support; Per-user command history; Commands dropped their historical "bgp " prefix:peer listinstead ofbgp peer list; A newze yangtool inspects the schema and command tree, including detecting completion collisions between sibling commands - Daemon & security hardening: SSH is now the only external interface to the daemon: Unix sockets, flock files, and PID files are gone, and
ze cli,signal,status,config edit,run, andshowall connect over SSH.ze initbootstraps the credential store andze startresolves the default config and launches the daemon. The daemon also now binds privileged ports as root and drops to a configured user/group afterward, and external plugin transport moved from Unix socketpairs to TLS. - Interop testing: GoBGP joins BIRD and FRR as a third interop target, and the interop test suite was rewritten in Python with 9 new scenarios.
Week of 2026-03-09
A big week for access, config safety, and BGP session security.
- Security & session hardening: TCP MD5 authentication for BGP sessions (RFC 2385), with platform-specific handling on Linux, FreeBSD, and macOS; An SSH server component (built on Charm Wish) with password auth and a per-session command UI, now the primary way to reach the CLI; RBAC authorization wired end to end: profile-based access control with validation, CLI testing support, and enforced deny/allow rules; A round of hardening across wire parsing, IPC, and config: path-traversal checks, tighter default bind addresses (SSH and metrics now default to localhost), message size limits, and closed timing windows on socket setup
- Config editing & safety: Config storage moved onto a dedicated blob-store backend (zefs), with atomic writes and path-traversal protection, backing config history, rollback, and diff; Concurrent config editing: sessions, conflict detection, and a set+meta format so multiple operators can edit safely; Commit confirmed, VyOS-style: commit with a countdown timer that auto-reverts unless confirmed; Config archive support for keeping named snapshots; Editor UX rounded out: auto-save on quit, auto-restore of a pending edit on restart, inline hints, a diff marker, split warnings, and a save command; Semicolons are now optional in config syntax, auto-inserted by the tokenizer
- CLI & operations: New
bgp log show/setandbgp metrics show/listcommands for runtime control and visibility;rib showgained community and AS-path regex filters, and output now supports yaml/json/table formats; Pipe operators in the interactive CLI, now with table as the default output; Per-peer and global RIB route metrics, plus per-type BGP counters (replacing the old generic message counters), exported to Prometheus; Graceful Restart now tracks staleness per route (RFC 4724), not just per peer;ze statuspromoted to a top-level command; Fish shell completion joins bash and zsh
Week of 2026-03-02
Real best-path selection landed, along with outbound route tracking and a round of CLI/editor polish.
- Routing: On-demand best-path selection in the RIB (
rib show best), covering LOCAL_PREF, AS_PATH length, ORIGIN, MED, eBGP/iBGP preference, ORIGINATOR_ID, and peer-address tiebreak per RFC 4271 Β§9.1.2; A new persistence plugin tracks outbound routes per peer, retaining cache entries on send and releasing them on withdrawal, then replays the full outbound set with End-of-RIB markers on reconnect; Graceful Restart Receiving Speaker support (RFC 4724 Β§4.2), with ADD-PATH state now threaded correctly through the format pipeline (RFC 7911); Fixed a watchdog bug where routes configured as withdrawn were being announced anyway on first session; FSM state transitions now cover the full RFC 4271 Β§8.2.2 table - CLI & editor: New
ze showandze runsplit: read-only commands vs. everything including destructive ones, each RPC now declares its own safety level; Dual-mode config editor (edit/command mode switching),ze config setwith YANG validation and--dry-run, andze config editnow offers to create a missing config file instead of failing; Command history (up/down arrow), "did you mean?" suggestions across CLI dispatch,--jsonoutput for schema commands, and shell completion for bash and zsh; New operational commands:bgp summary, peer capabilities,peer clear soft, andconfig diff(text and JSON); Fixed a capability-negotiation bug where comparisons only checked byte counts instead of actual wire bytes - Under the hood: Panic recovery now wraps every long-lived BGP goroutine (peer loop, delivery, listener, reactor monitor): a fault inside one peer tears down and re-establishes that session instead of crashing the daemon. Builds now report a version (YY.MM.DD) and build date.
Week of 2026-02-23
A route-server-focused week: reliability fixes for BGP Route Server under load, a new external plugin protocol option, and systematic config validation.
- Route Server (RFC 7947): The route-server plugin is renamed from bgp-rr to bgp-rs to match what it actually does (forward-all Route Server semantics, not Route Reflector client/non-client selection);
rs status/rs peerscommands replace the oldrrnames.; Reconnecting peers now get a targeted replay of just their own routes from a dedicated adj-rib-in plugin, instead of triggering a full ROUTE-REFRESH storm across every peer and family; Fixed several route-loss bugs under backpressure: an overflow buffer stops silent drops when a peer can't keep up, and per-entry cache acknowledgment prevents cumulative eviction from losing routes; Plugins can now declare dependencies on each other (route-server on adj-rib-in, for example), auto-loaded and validated at startup - Plugin protocol: External plugins can now speak a simple line-based text protocol instead of JSON-RPC for their startup handshake and event delivery, an easier path for writing plugins in languages other than Go.
- Config validation: YANG config trees are now validated recursively against schema (enums, ranges, patterns, mandatory fields), with an extensible
ze:validatemechanism for custom runtime checks. - Under the hood: Event delivery, IPC framing, and TCP session reads got a round of allocation and syscall reduction: zero-alloc text formatting, batched IPC delivery, buffered TCP reads, and RPC calls without a goroutine per request.
- ze-chaos: The chaos-testing dashboard got a UX pass: live convergence charts, a peer health view, and clearer sync-state visibility (peers now show Established β Syncing β Up instead of jumping straight to Up).
Week of 2026-02-16
A hard round of route reflector hardening, a live web dashboard for the chaos tool, and a batch of BGP protocol and config improvements.
- Route reflector hardening: The route reflector had a rough week of bug-hunting and came out solid. Fixes landed for routes being dropped under a slow consumer, deadlocks from subscribing to both directions of a session, incorrect per-family filtering, and log spam during backpressure. The UPDATE cache is now refcounted with configurable size and TTL, out-of-order acknowledgements are treated as no-ops instead of protocol violations, and forwarding moved to per-source and per-destination worker pools so one slow peer no longer stalls the others. Shutdown got faster too: sequential per-component timeouts that used to compound are now parallel waits under a single deadline, making daemon stop near-instant.
- Chaos tool dashboard: The chaos testing tool (now renamed
ze-chaos) gained a live web dashboard (--web :8080) with real-time SSE event streaming, a peer status grid, a route matrix heatmap, and pause/resume/rate controls. Underneath it: an in-process simulation mode with virtual time that runs over 100x faster than driving real TCP connections, a set of composable RFC property assertions (route consistency, convergence deadlines, no duplicate routes, hold-timer enforcement, message ordering) checked against every run, and a shrink engine that reduces a failing run down to a minimal reproduction automatically. Chaos fault injection can now also be wired directly into a running Ze process via CLI flag, environment variable, or config. - A new IETF draft: ATTR_TOMBSTONE: RFC 7606's "attribute discard" action says a malformed attribute MUST be; removed and the UPDATE continues to be processed. The conventional way to do; that is to rebuild the whole path attributes section: shift every attribute; after the bad one down to close the gap, then recompute the path attributes; length, the UPDATE's total length, and any offsets an implementation cached; while parsing.; There's a cheaper trick: overwrite the malformed attribute in place with an; unused attribute code instead of removing it. Nothing moves, no length field; changes, and any offsets already computed for the rest of the message stay; valid. This already works against any conformant BGP speaker today, no new; RFC required, because RFC 4271 already specifies safe handling of attributes; a speaker doesn't recognize.; Ze started enforcing RFC 7606 error handling this week and implemented; exactly this: attribute-discard markers written in place, first under the; name ATTR_DISCARD (and a first draft,
draft-mangin-idr-attr-discard-00).; A few days later both got renamed to ATTR_TOMBSTONE, with the draft revised; to match: a specific, reserved code point with a defined value format; (which attribute got discarded, and why), so implementations that adopt it; are speaking the same language instead of each inventing their own; incompatible version of the same trick. It's the same principle behind Ze's; own wire encoding: operate on the buffer in place instead of copying it. - Protocol and config: Duplicate router IDs within the same AS are now rejected on OPEN per RFC 4271 Β§4.2; All BGP capabilities (ASN4, route refresh, extended message, add-path, graceful restart, extended next-hop) now share the same four enforcement modes as address families: enable, disable, require, refuse; Peers can each bind a dedicated listen port, so multiple peers can run on 127.0.0.1 without loopback aliases; The
passiveboolean peer option was replaced with aconnectionmode (both/passive/active) for clearer intent; Config gained presence containers, inline list syntax, and an extended-community length suffix - Under the hood: BGP capability handling (route refresh, graceful restart, hostname, software version) moved out of the core engine into independent plugins, and a lightweight "summary" subscription format was added for consumers that only need announce/withdraw and family information rather than fully decoded attributes.
Week of 2026-02-09
A new chaos-testing tool, matured config reload, RFC 7606 enforcement, and a hot-path allocation cleanup.
- Chaos testing tool: A new dedicated tool,
ze-bgp-chaos, landed this week: a seed-based fault-injection harness for exercising Ze's BGP route propagation. It grew from a single-peer session driver into a multi-peer validation framework with scripted chaos events (drops, resets, malformed messages) and coverage for seven address families (IPv4/IPv6 unicast, IPv4/IPv6 VPN, EVPN, IPv4/IPv6 FlowSpec). - Config reload: Live reload now runs through the hub/orchestrator architecture: plugins get a verify pass before an apply pass, and the reload coordinator is hardened so a crashing plugin can't corrupt the process (any plugin that dies mid-reload aborts the reload cleanly instead of applying a partial config). Committing in the config editor now triggers a live daemon reload over the API socket directly. A new
ze signalcommand plus PID-file locking makes it possible to reload, stop, or query a running daemon without hunting down its PID, and prevents two instances from starting against the same config. - Protocol correctness: Malformed UPDATE messages are now handled per RFC 7606: depending on the error, Ze treats the route as withdrawn, discards just the bad attribute, or resets the session, instead of one blunt response for every case; Early support for RFC 9234 BGP Roles: peers can declare a role, and the engine validates role pairs on OPEN, sending a NOTIFICATION on mismatch (OTC handling is still to come);
local-addressis now mandatory for every peer; leaving it unset made TCP source IP selection OS-dependent and produced inconsistent next-hop-self behaviour - ExaBGP migration: The migration tool now passes all 37 compatibility test configs, with L2VPN/VPLS migration completed and ExaBGP watchdog processes bridged through Ze's API socket.
- Performance: The BGP UPDATE encoding path had its remaining heap allocations eliminated: attribute writes, SRv6 TLVs, withdrawals, and RIB NLRI paths all now write into pooled buffers instead of allocating per message.
Week of 2026-02-02
Mostly spent on the config editor, a new capability, and a round of decode/RIB bug fixes.
- Link-local next-hop capability: A new plugin adds the link-local-nexthop capability (code 77, draft-ietf-idr-linklocal-capability), a zero-payload flag signalling willingness to receive IPv6 link-local addresses as BGP next-hops per RFC 2545 Β§3.
- Config editor: The
setcommand now actually modifies config (it was a stub before), and theloadcommand was redesigned with explicit syntax:load <file|terminal> <absolute|relative> <replace|merge>, including a paste-from-terminal mode. Peer names containing spaces, quotes, or backslashes are now handled correctly inedit/set, and tab completion for peer selectors shows actual configured peers instead of schema field names. - Fixes: A plugin RPC routing bug sent commands like
bgp watchdog announceandbgp cache listto the wrong handler; both now dispatch correctly; Decoded IPv6 NLRI now returns plain prefix strings, matching IPv4 output instead of wrapping them in an extra object; RIB event parsing now correctly reads sent UPDATE events in Ze's JSON format, fixing route replay for reconnect and graceful-restart scenarios; A capability decoder bug that rejected flag-only capabilities with no payload (breaking the new link-local-nexthop plugin) is fixed; Early ExaBGP migration work: automatic Extended Message capability (RFC 8654) and hostname/domain-name migration to the hostname capability block
Week of 2026-01-26
Config work, the ExaBGP migration path, and correctness fixes across the wire.
- Family plugins: BGP-LS, VPN, EVPN and FlowSpec are now standalone family plugins with their own CLI decode/encode mode, human-readable output by default, and JSON or text input. A two-phase startup (explicit plugins first, then auto-load by family) avoids conflicts when more than one plugin could claim the same NLRI type. Capability decoding is plugin-driven too: unknown capabilities now show as
code=Nwith raw hex instead of being opaque, and a new hostname (FQDN) capability plugin injects per-peer hostname/domain into the OPEN message. - ExaBGP migration: The ExaBGP config migration tool now converts
announce/staticblocks to Ze's nativeupdate {}syntax across all 38 test configs (up from 2). Legacy ExaBGP config syntax (announce/static/flow/l2vpn) has been removed from Ze entirely; route announcements now go exclusively through nativeupdate { attribute {} nlri {} }blocks, which also gained watchdog support for route withdrawal control. - Correctness fixes: AS_PATH prepending is now RFC 4271 compliant: Ze no longer double-prepends the local AS when the configured path already starts with it; Connection collision resolution (RFC 4271 Β§6.8) no longer risks a panic under load; it uses proper channel synchronization for session teardown instead of a timed sleep; An explicit
hold-time 0(disable keepalives, RFC 4271) is preserved instead of being silently reset to the 90s default; Route Distinguisher is now parsed inline with the NLRI (as RFC 8955/4364 define it) instead of as a path attribute, consistent across API, config, and VPN families; FlowSpec's OR-of-AND filter encoding now round-trips correctly - Config editor and CLI: The editor gained mandatory peer-as validation with template inheritance, a prompt to resume pending edits left from a previous session, and a new
ze config editcommand.config check,dump,migrate,validateandschemaall accept input on stdin now, useful for scripting. - Under the hood: RIB storage moved to per-attribute deduplication, cutting memory use for peers carrying large overlapping route sets.
Week of 2026-01-19
A big architecture week: Ze split into a hub process and a BGP child process, gained live config reload, and got a documented plugin SDK.
- Process architecture: Ze now starts as a hub/orchestrator process (
ze config.conf) that forks BGP as a separate child process, coordinating startup with plugins over a multi-stage handshake (declare, configure, negotiate capabilities, register, ready). Config can be reloaded live with SIGHUP: the reactor re-parses the file, diffs peers, and adds or removes sessions without a restart. - Plugin SDK: A new SDK and developer guide (protocol details, YANG schema authoring, verify/apply handlers, command registration, testing) makes it possible to write BGP plugins outside the core tree, with a working example included. Plugins now declare a load priority so verify/apply runs in a predictable order across plugins.
- Config validation: Configuration is validated against YANG schemas (peer, peer-group, route-map, prefix-list, plugin config), with range and pattern constraints checked before anything is applied. The config editor validates as you type (debounced, with an error count in the status bar) and enforces RFC 4271's hold-time rule (0 or 3+ seconds), blocking commit while errors remain. Unsaved edits now persist between editor sessions.
- Config syntax: BGP configuration is now wrapped in a
bgp {}block, with template inheritance for peer groups, laying groundwork for other protocols to sit alongside BGP in the same config file. - CLI: Daemon and peer commands moved under a
bgpnamespace (bgp daemon,bgp peer <selector>) for a more consistent command surface, alongside new RIB introspection and event-subscription commands. - Fixes: VPN routes carrying an SRv6 Prefix-SID were silently dropping the attribute; it's included correctly now; JSON output places next-hop consistently across all NLRI families (FlowSpec had it in a different spot than everything else)
Week of 2026-01-12
A week focused on Graceful Restart, ExaBGP migration tooling, and logging.
- Graceful Restart: A dedicated Graceful Restart plugin now handles per-peer restart-time configuration and registers the GR capability with peers during session startup, building on the plugin system's new per-peer capability support.
- ExaBGP migration: For anyone running ExaBGP today, Ze picked up a migration path:;
zebgp exabgp migrateconverts ExaBGP configs to Ze's format (neighbor -> peer syntax, capability normalization, automatic wiring of the RIB plugin when graceful-restart or route-refresh is in use);zebgp exabgp pluginruns existing ExaBGP process plugins under Ze via a bridge that translates JSON and commands both ways; The bridge forwards negotiated capabilities and next-hop information to those plugins, including RFC 8950 extended next-hop handling - Logging: Per-subsystem logging landed, with
SLOG_LEVELto control verbosity and debug logging available where needed. - Config & API: The text-based update API now covers end-of-RIB markers, VPLS, and EVPN routes; EVPN Type 5 routes support the RFC 9136 gateway keyword for overlay index resolution; Plugin startup timeouts are now configurable per plugin; Config validation now catches route-refresh or graceful-restart enabled without a process to resend routes, instead of failing silently later
Week of 2026-01-05
This week rounded out route-refresh, ADD-PATH and VPN/labeled-unicast support in the plugin API, alongside a batch of BGP correctness fixes.
- Route refresh: Enhanced Route Refresh (RFC 7313) is now handled end to end: a refresh request gets a Begin-of-RR, the matching routes, then an End-of-RR, and the capability negotiation bug that stopped BoRR/EoRR from ever being sent when
route-refreshwas configured is fixed. Newmsg-id retain/release/expire/listcommands let an API program control how long UPDATE messages stay cached, which graceful-restart tooling can use to replay routes. - Plugin API: routes and families: ADD-PATH (RFC 7911) path-ids are now preserved through the plugin event stream, so plugins can tell multiple paths to the same prefix apart; A FlowSpec text-mode parser (RFC 8955) covering all twelve match-component types and both numeric and bitmask operators; Route distinguisher and label support for VPN and labeled-unicast routes in the text API, including multi-label stacks (RFC 8277);
AnnounceL3VPN/WithdrawL3VPNcommands for RFC 4364 MPLS VPN routes; Raw wire-format input: routes and attributes can now be passed as hex or base64 BGP bytes directly, and a passthrough command sends fully unvalidated bytes for protocol testing; Per-session control over which wire encoding (hex, base64, CBOR or text) an API program uses, independently for each direction; Plugins now go through a defined startup handshake with the core: declare capabilities and commands, receive matching config, register their OPEN-message capabilities, then signal ready before sessions start - Protocol correctness: UPDATE messages built via the text API always include ORIGIN and AS_PATH, the two RFC 4271 mandatory attributes that could previously be missing; Fixed attribute ordering in batched UPDATE messages (AS_PATH and NEXT_HOP were landing in the wrong position, and iBGP sessions were missing LOCAL_PREF); MUP routes announced via the API were silently dropping their extended-community attribute; Label-only routes are now correctly classified as labeled-unicast (SAFI 4) instead of MPLS VPN
Week of 2025-12-29
Route-family coverage rounded out (labeled-unicast, MPLS VPN, MUP, route reflection), a batch of protocol-correctness fixes, and a security-relevant change to how Ze listens for BGP sessions.
- Session hardening: Ze no longer binds one global BGP listener. Listeners are now derived automatically from each peer's configured local address, so BGP is only exposed on interfaces that actually have a peer configured. This is a breaking change: the old TCP.Bind environment variable is gone, and every peer needs a local address set.
- Route families: Labeled-unicast (SAFI 4) routes, including BGP Prefix-SID, now round-trip through the API with full Adj-RIB-Out support.; MPLS VPN (L3VPN) routes can be announced directly from config announce blocks, and the split /N syntax already used for plain routes now works for VPN routes too.; MUP (SAFI 85) routes can be announced and withdrawn via the API.; Route reflector attributes (ORIGINATOR_ID, CLUSTER_LIST) are now attached consistently across MVPN, FlowSpec, and MUP routes, not just plain unicast.; A standalone route reflector API server (
zebgp api rr) exposes peer and RIB state over its own endpoint. - Protocol correctness: AS_PATH and AGGREGATOR now encode correctly under 4-octet ASN negotiation (RFC 6793).; Path attributes are emitted in RFC 4271 Appendix F.3 order.; FlowSpec VPN routes now carry their Route Distinguisher in the NLRI, as RFC 8955 requires.; IPv6 unicast routes can carry an IPv4-mapped next-hop (RFC 8950).; Routes redistributed through the RIB keep their original path attributes and LOCAL_PREF instead of losing them in transit.
- CLI & config: New
zebgp decodecommand turns raw hex BGP messages into JSON.; Newzebgp encodecommand does the reverse: turns a route command into wire-format hex, with round-trip verification across every supported family.; Config gained anenvironmentblock.; Community values in config now accept bare integers and hex, not just the named forms.; API attribute and NLRI filters let external processes subscribe to a narrower slice of updates instead of the full stream.; The config editor moved fromzebgp edittozebgp config edit. - Reliability: Session teardown and reconnect handling is more robust.; A data race in process shutdown is fixed, and processes now receive a shutdown signal before termination instead of being killed outright.; Peer up/down transitions are now pushed to attached API processes as state notifications.
Week of 2025-12-22
Work on the BGP engine itself: route encoding correctness, session robustness, and a first real API surface for driving peers programmatically.
- Protocol correctness: Extended communities now parse hex format per RFC 4360; ADD-PATH encoding (RFC 7911), including for VPN routes; End-of-RIB markers are now sent for every negotiated address family (RFC 4724); Extended next-hop encoding per RFC 8950; AS_PATH validation fixed against RFC 5065; IPv6 announcements and withdrawals now correctly use MP_REACH_NLRI / MP_UNREACH_NLRI instead of IPv4-style NEXT_HOP; EVPN routes (all 5 route types) and L3VPN (MPLS VPN) route announcement support; Route Leak Prevention via the OTC attribute (RFC 9234); Revised UPDATE error handling for malformed attributes (RFC 7606): partial-attribute discard instead of session teardown, plus IBGP-context and 4-octet AS validation; Labeled-unicast (SAFI 4) now supports split announcements, and route announcements support
/Nsplit syntax generally; Fixed a bug where withdrawals weren't actually being sent and route stats were wrong; Fixed iBGP attribute handling for API-announced routes - Session and process handling: BGP connection collision detection per RFC 4271 Β§6.8; Backpressure and respawn limits for connected processes, so a misbehaving process can't take down the session
- API: A real command surface for controlling BGP sessions and routes is taking shape:; Session-level commands: status, enable, disable; RIB flush/clear commands; Route commit transactions: named, concurrent commits with announce/withdraw, rollback, and end-of-RIB signaling; Watchdog-controlled routes: named pools of routes that announce or withdraw together, state persisting across reconnects; A teardown command with an ordered operation queue;
announce attributes/nlri/updatecommands with batch NLRI support; Inbound UPDATEs are now forwarded to connected processes
Week of 2025-12-15
The first tracked week of development on Ze. In seven days the BGP engine went from nothing to a config-driven daemon that speaks the wire protocol, holds a RIB, and tests itself against ExaBGP.
- Core BGP engine: The foundational pieces of a BGP speaker landed: wire-format encoding/decoding, all BGP message types, capability negotiation, path attributes, NLRI types, a RIB, the finite state machine, and the session/reactor layer that drives peer connections. A zero-copy byte-deduplication pool underpins the encoding path from the start.
- Config and CLI: A schema-driven config parser landed with ExaBGP-compatible syntax (set-style blocks, arrays, serialization), wired straight through to the reactor. The CLI grew daemon and API run modes plus an interactive editor with autocomplete.
- API and self-check testing: An API layer for external processes to talk to Ze, alongside a functional self-check test harness and a testpeer package that exercises the daemon against ExaBGP for compatibility, including passive-peer handling.
- RFC compliance pass: A broad pass brought the engine's attribute and NLRI handling in line with the relevant RFCs: EVPN Type 1, Type 4, and Type 5 (RFC 7432), BGP-LS, MVPN, VPLS, and FlowSpec VPN (SAFI 134) route support, extended next-hop encoding (RFC 5549/8950), AFI/SAFI family validation (RFC 4760), VPN next-hop RD parsing (RFC 4364/4659), MP-NLRI chunking (RFC 4271), AS_CONFED handling in AS4_PATH and ASN4-aware AS_PATH encoding (RFC 6793), and path attribute ordering (RFC 4271 Appendix F.3). Fixes went in for extended community parsing, FlowSpec numeric match operators, software-version capability parsing, and IPv6 route sending with correct end-of-RIB markers.
- Config migration and batched updates: Config syntax moved from
neighbortopeer, withstaticroutes migrating toannounce, template-basedgroup/matchblocks, peer glob patterns (peer 192.168.*.*), and CLI commands to check and migrate older configs. Per-family negotiation now supports enable/disable/require modes plus a lenient ignore mode for UPDATE validation. On the sending side, routes are now grouped by shared attributes and packed into batched UPDATE messages per peer, with per-peer Adj-RIB-Out, transactional commits, and a CommitService that flushes and sends grouped UPDATEs as a unit.