-
Notifications
You must be signed in to change notification settings - Fork 2
configuration interfaces
Pre-Alpha. This page describes behavior that may change.
Ze manages Linux network interfaces through the iface component, backed by pure netlink. No iproute2 shell-outs. The model is two-layer JunOS-style: physical interfaces at the top level, logical units underneath. Interfaces carry a logical name chosen by the operator, are bound to a kernel device through a shared resolver, and are discovered automatically when you run ze init.
The logical name is decoupled from the kernel device. Every subsystem that takes an interface (IS-IS, routing, DHCP, the iface CLI ops) refers to the logical name and goes through one central resolver in the iface component. Consumers never resolve a kernel device directly, so the binding selectors (os-name, mac { match }) are honored uniformly everywhere.
This page covers the configuration surface. The in-tree features list is the authoritative capability map and the ground truth for which features exist today.
interface {
ethernet uplink {
mac {
address 00:1a:2b:3c:4d:5e;
}
}
ethernet mgmt {
mac {
address 00:1a:2b:3c:4d:5f;
}
mtu 1500;
}
bridge fabric {
mac {
address 00:1a:2b:3c:4d:60;
}
stp true;
}
dummy blackhole {
}
loopback {
}
}
| Type | MAC required | Notes |
|---|---|---|
ethernet |
Yes | Physical Ethernet interface. |
veth |
Yes | Virtual Ethernet pair. |
bridge |
Yes | Bridge interface. STP optional. |
dummy |
No | Virtual dummy interface. |
loopback |
No | Container, no key. |
tunnel |
Depends | GRE/IPIP/SIT/IP6TNL. gretap and ip6gretap require MAC. |
wireguard |
No | WireGuard encrypted tunnel with peer reconciliation. |
pppoe-client |
No | PPPoE client (RFC 2516). Dials AC over a physical Ethernet interface. |
xfrm |
No | XFRM interface for route-based IPsec. See IPsec VPN. |
The mac container carries two independent leaves. mac { address } overrides the operational MAC and is the binding shown above. mac { match } selects which kernel device a logical name resolves to by hardware MAC (see Binding by hardware MAC). They are independent: a NIC can be matched by its permanent MAC and have its operational MAC overridden at once.
The name under interface { ethernet <name> { } } is a logical, human-readable handle you choose. It is not necessarily the OS interface name.
By default the logical name is also used as the kernel device name, so every interface whose name already matches its kernel device resolves unchanged. A shared resolver in the iface component maps each logical name to its kernel device and serves the ifindex, MAC, MTU, and addresses. Every operator-facing operation that takes an interface goes through this one resolver: the iface CLI ops (set MTU, add/remove address, admin up/down, bridge, mirror), the DHCP client socket binding, and the routing and protocol consumers all act on the bound kernel device.
No consumer resolves a kernel device on its own. A checks gate, make ze-iface-resolution-check, scans the tree and fails the build for any new direct kernel resolution (netlink.LinkByName, net.InterfaceByName, the SIOCGIFINDEX ioctl) outside a small justified allowlist. New consumers must call iface.Resolve / iface.Addresses / iface.Subscribe or the dispatch ops, so the binding selectors below are honored everywhere instead of forcing the logical name to equal the kernel device.
To alias a logical name to a different kernel device, set the os-name selector on an ethernet interface:
interface {
ethernet uplink {
os-name eth0; # logical "uplink" binds to kernel device eth0
}
}
Now isis { interface uplink { } }, an address add on uplink, and every other reference resolve to kernel device eth0. The os-name selector applies to ethernet interfaces, the kind Ze matches against pre-existing kernel devices. Created kinds (dummy, veth, bridge, tunnels, wireguard, xfrm) are made by Ze under their logical name, so os-name is ignored on them and the logical name is always the kernel device name.
Names and OS device names can change between boots (NIC reordering, slot moves). To pin a logical interface to a physical NIC regardless of the name the kernel gives it, select the device by its hardware MAC with mac { match }:
interface {
ethernet uplink {
mac {
match a0:36:9f:12:34:56; # bind "uplink" to the NIC with this MAC
}
}
}
The resolver scans every interface and binds uplink to the one carrying that MAC. It matches the device's permanent (factory) address (IFLA_PERM_ADDRESS) when the NIC reports one, so the binding survives an operational MAC override (mac { address }) on the very same interface. For virtual devices that report no permanent address it matches the current address instead. When no device carries the MAC the binding defers until the device appears; the resolver fires a link event then and attaches. So a logical name follows the NIC across kernel renames.
mac { match } takes precedence over os-name and, like os-name, applies to ethernet only. For ethernet, veth, and bridge interfaces, mac { address } is required to override the operational MAC and must be unique within each type; mac { match } is optional and independent.
ze init discovers every OS network interface via netlink (Linux) or stdlib (other platforms) and writes initial configuration entries. Each discovered interface gets an entry named after its OS name at discovery time, with mac { address } populated and the os-name selector recording the original OS device name. Loopback appears as an empty loopback { } container.
The generated config is a starting point. Rename the entries to something descriptive: the os-name selector keeps mapping the renamed entry back to the kernel device, and switching to mac { match } keeps the link to the physical NIC even when the kernel renames it.
A physical interface can carry multiple logical units, in the JunOS sense. Units are named (lowercase alphanumeric and hyphens). A default unit is implicit and does not need to be declared. Units with a VLAN tag are declared explicitly.
interface {
ethernet uplink {
mac {
address 00:1a:2b:3c:4d:5e;
}
unit main {
ipv4 {
address [ 10.0.0.1/24 ];
}
ipv6 {
address [ fd00::1/64 ];
}
}
unit vlan100 {
vlan-id 100;
ipv4 {
address [ 172.16.0.1/24 ];
}
}
}
}
Creating a unit with a VLAN tag creates a VLAN subinterface. Removing the unit removes the subinterface.
VLAN units support ingress and egress QoS maps that translate between 802.1p PCP values and internal Linux priority levels. Configure them under the unit:
unit vlan100 {
vlan-id 100;
qos {
ingress-map [ 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 ];
egress-map [ 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 ];
}
}
Each entry is priority:pcp (ingress) or priority:pcp (egress). Named class-of-service profiles can be assigned at the interface or unit level via the cos plugin. See Class of Service for the full profile and RADIUS integration.
IPv4 and IPv6 addresses live under per-family containers inside units. Use bracket syntax for the address list.
unit main {
ipv4 {
address [ 10.0.0.1/24 10.0.0.2/24 ];
}
ipv6 {
address [ fd00::1/64 ];
}
}
Multiple addresses per family per unit are supported. The monitor subscribes to netlink multicast and emits bus events on address added, address removed, and DAD completion. IPv6 addresses with IFA_F_TENTATIVE are held until DAD completes.
DHCPv4 and DHCPv6 are handled by the iface-dhcp plugin. Enable per-unit inside the per-family containers.
interface {
ethernet uplink {
mac {
address 00:1a:2b:3c:4d:5e;
}
unit main {
ipv4 {
dhcp {
enabled true;
}
}
ipv6 {
dhcpv6 {
enabled true;
}
}
}
}
}
Both address families can run concurrently. Leases are installed directly via netlink and the bus emits interface/dhcp/lease-acquired, lease-renewed, and lease-expired events with the address, prefix, router, DNS servers, and lease time.
Bridges carry member ports in their sub-container.
interface {
bridge fabric {
mac {
address 00:1a:2b:3c:4d:60;
}
stp true;
member [ port1 port2 ];
}
ethernet port1 {
mac {
address 00:11:22:33:44:55;
}
}
ethernet port2 {
mac {
address 00:11:22:33:44:56;
}
}
}
Member ports are listed on the bridge itself, referring to ethernet interfaces by their Ze name, not by the OS name.
A handful of per-interface sysctls are exposed as config leaves inside the per-family containers on each unit.
| Leaf | Covers |
|---|---|
ipv4 { forwarding } |
IPv4 forwarding. |
ipv4 { arp-filter }, arp-accept, arp-announce, arp-ignore
|
ARP behaviour. |
ipv4 { proxy-arp } |
Proxy ARP. |
ipv4 { rpf-check } |
Reverse path filtering: strict, loose, or disable. |
ipv6 { autoconf } |
SLAAC on the interface. |
ipv6 { accept-ra } |
0, 1, or 2. |
ipv6 { forwarding } |
IPv6 forwarding. |
ipv6 { rpf-check } |
Reverse path filtering (VPP data plane only on IPv6). |
Ze writes these directly to /proc/sys/net/ipv4/... or /proc/sys/net/ipv6/... via procfs.
Per-interface offload settings live in an offload container on L2 interface kinds (ethernet, veth, bridge, dummy). Each feature is a boolean: true to enable, false to disable, absent to leave at OS default.
interface {
ethernet uplink {
mac {
address 00:1a:2b:3c:4d:5e;
}
offload {
gro true;
tso false;
rps true;
}
}
}
| Leaf | Description |
|---|---|
gro |
Generic Receive Offload. Software-based receive aggregation. |
gso |
Generic Segmentation Offload. Delayed send segmentation. |
sg |
Scatter-Gather I/O. Required by TSO/GSO on most drivers. |
tso |
TCP Segmentation Offload. Hardware-based send segmentation. Disable for VPP. |
lro |
Large Receive Offload. Hardware receive coalescing. Disable on routers/bridges. |
hw-tc-offload |
Hardware TC offload (flower/u32 filter rules in NIC firmware). |
rps |
Receive Packet Steering. Software multi-CPU receive distribution. |
rfs |
Receive Flow Steering. Steer to the CPU running the consuming application. |
Applied directly via kernel ioctl (SIOCETHTOOL) or sysfs. No ethtool binary required. Unsupported features are logged as warnings and do not block config commit.
Ingress and egress mirroring via tc mirred is supported and idempotent. The mirror container under an interface names the source and the destination, and Ze manages the tc setup and cleanup.
The BGP reactor subscribes to the interface bus. When an address is added or removed on a unit that a BGP listener is bound to, the reactor starts or stops the listener automatically. When an address is migrated make-before-break (see below), the reactor signals bgp/listener/ready once the new listener is up, and the old listener is torn down only after that.
When you move an address from one interface or unit to another, Ze runs a five-phase migration.
- Add the new address.
- Wait for DAD on the new address.
- Signal BGP readiness on the new address.
- Update the local state.
- Remove the old address.
Each phase has a rollback path, so a failure during migration does not leave the interface in a broken state. The CLI command is:
ze interface migrate --from uplink.0 --to new-uplink.0 --address 10.0.0.1/24 --timeout 30sZe supports GRE, IPIP, SIT, and IP6TNL tunnel families via netlink.
interface {
tunnel gre-to-dc2 {
encapsulation {
gretap {
local { ip 192.0.2.1; }
remote { ip 198.51.100.1; }
mac {
address 00:1a:2b:3c:4d:70;
}
}
}
unit main {
ipv4 {
address [ 10.255.0.1/30 ];
}
}
}
tunnel sit-v6over4 {
encapsulation {
sit {
local { ip 192.0.2.1; }
remote { ip 198.51.100.2; }
}
}
unit main {
ipv6 {
address [ fd00::1/64 ];
}
}
}
}
| Type | Description |
|---|---|
gre |
GRE point-to-point tunnel. |
gretap |
GRE L2 tunnel (carries Ethernet frames). Requires mac { address }. |
ipip |
IPv4-in-IPv4 tunnel. |
sit |
IPv6-in-IPv4 tunnel. |
ip6gre |
GRE over IPv6. |
ip6gretap |
GRE L2 over IPv6. Requires mac { address }. |
ip6tnl |
IPv6-in-IPv6 tunnel. |
WireGuard interfaces are configured under interface { wireguard <name> { ... } }. Ze manages the interface via wgctrl and reconciles peers on config reload.
interface {
wireguard wg0 {
private-key "<base64 key>";
listen-port 51820;
peer remote-site {
public-key "<base64 key>";
endpoint { ip 198.51.100.1; port 51820; }
allowed-ips [ 10.0.0.0/24 fd00::/64 ];
persistent-keepalive 25;
}
unit main {
ipv4 {
address [ 10.10.0.1/24 ];
}
ipv6 {
address [ fd00::1/64 ];
}
}
}
}
Peers are reconciled on commit: added peers are created, removed peers are deleted, changed peers are updated in place. Interface deletion during reconciliation is also handled.
The route-priority leaf on a unit controls the metric applied to routes learned from DHCP or other dynamic sources on that interface. Lower values mean higher priority.
unit main {
ipv4 {
dhcp { enabled true; }
}
route-priority 100;
}
When VPP is configured, interfaces can use the VPP backend instead of netlink:
interface {
backend vpp;
}
The VPP backend manages interface lifecycle (create, delete, admin up/down, MTU), addressing, bridge port membership, and monitoring via GoVPP. See VPP for the full data plane story.
Ze manages IPv6 default routes from Router Advertisements. When an interface has accept-ra enabled, RA-derived default routes are installed and removed as advertisements arrive and expire.
show interface <name> renders a detail block keyed by the logical name. The resolver translates the logical name to its kernel device first, so the output reports the actual bound device and its hardware identity, including the permanent (factory) MAC the mac { match } selector binds against.
Name: uplink
OS Name: eth0
Index: 3
Type: ethernet
State: up
MTU: 1500
MAC: 02:11:22:33:44:55
Perm MAC: a0:36:9f:12:34:56
Addresses:
10.0.0.1/24 (inet)
| Field | Meaning |
|---|---|
Name |
The logical name from config. |
OS Name |
The kernel device the logical name resolved to. Shown when it differs from, or aliases, the logical name. |
MAC |
The operational (current) MAC, including any mac { address } override. |
Perm MAC |
The permanent (factory) MAC (IFLA_PERM_ADDRESS). Omitted for virtual devices that report none. This is the address mac { match } binds to, so it stays stable across an operational override. |
The ze interface scan command discovers all OS interfaces via netlink and reports them, useful for initial setup and troubleshooting.
Ze supports PPPoE client interfaces for CPE/subscriber use. The pppoe-client kind dials an access concentrator over a physical Ethernet interface, negotiates LCP/auth/IPCP, and presents the resulting PPP session as a routable interface with server-assigned addresses.
interface {
pppoe-client pppoe0 {
source-interface eth2;
authentication {
username "user@isp.example";
password "secret";
}
}
}
| Leaf | Description |
|---|---|
source-interface |
Physical Ethernet interface for PPPoE discovery (required). |
authentication / username |
Authentication username sent to the AC (required). |
authentication / password |
Authentication password, stored |
service-name |
Desired PPPoE service name. Empty means accept any. |
ac-name |
Desired access concentrator name. Empty means accept any. |
no-default-route |
Do not install a default route via the PPP interface. |
The kernel PPP interface (pppN) is created dynamically. The name leaf is a config key only.
XFRM interfaces provide route-based IPsec. Traffic routed through the XFRM interface is encrypted by the kernel's XFRM subsystem; traffic arriving on it is decrypted. Ze manages XFRM interface creation and deletion via netlink.
interface {
xfrm ipsec0 {
if-id 42;
unit main {
ipv4 {
address [ 10.255.0.1/30 ];
}
}
}
}
| Field | Type | Description |
|---|---|---|
if-id |
uint32 | XFRM interface ID, must match the IPsec SA's if-id. |
XFRM interfaces are typically paired with IPsec tunnel configuration. See IPsec VPN for the IKE and SA setup.
Ze samples interface counters every second and computes per-interface rates for rx/tx bytes, packets, errors, and drops.
show interface rate # All interfaces
monitor interface rate # Live streamingTwelve Prometheus gauges under ze_interface_* expose the rates. The web UI includes rate columns in the interface table.
A few things you would expect on a more mature network OS are not in Ze. The honest list: bonding and LACP, VXLAN, VRF route isolation, VRRP, physical-layer tuning (speed, duplex, autoneg), and 802.1X. The capability table in the in-tree interfaces features page has the full list.
- In-tree interfaces feature page for the capability matrix.
-
Operation: command reference for
ze interfaceandze show interface. - FIB for how routes reach the kernel forwarding table after interfaces are configured.
- VPP for the VPP data plane integration.
Adapted from main/docs/features/interfaces.md and main/docs/guide/configuration.md.
Unreviewed draft. This wiki was authored in bulk and has not been reviewed. File corrections on the issue tracker.
- Overview
- YANG Model
- Editor Workflow
- Archive and Rollback
- System
- Interfaces
- VRRP
- BFD
- FIB
- OSPF
- IS-IS
- MPLS / LDP / RSVP-TE
- RSVP-TE
- SRv6
- Static Routes
- Policy Routing
- Firewall
- Traffic Control
- Class of Service
- L2TP/PPP
- PPPoE
- VPP Data Plane
- RPKI
- IPsec VPN
- TACACS+ AAA
- RADIUS AAA
- AS112 DNS
- Authorization
- Fleet
- BGP
- Starting and Stopping
- Show Commands
- Monitoring
- Flow Export
- DDoS Mitigation
- Anomaly Detection
- Health Checks
- Audit Trail
- Production Diagnostics
- Logging
- Operational Reports
- Healthcheck
- Self-Update
- Zero-Touch Provisioning
- MRT Analysis
- Upgrade and Restart
- Storage
- Policy
- Core
- Resilience
- Validation
- Capabilities
- Address Families
- Protocol
- Subsystems
- Infrastructure
- Route Server at an IXP
- Transit Edge with RPKI
- Public Looking Glass
- ExaBGP Migration Walkthrough
- FlowSpec Injection
- Chaos-Tested Peering
- AS Path Topology