Skip to content

configuration interfaces

Thomas Mangin edited this page Aug 16, 2026 · 9 revisions

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.

The type list

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.

Logical name and the resolver

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.

The os-name selector

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.

Binding by hardware MAC

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.

Discovery during ze init

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.

Logical units

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 802.1p QoS maps

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.

Addressing

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.

The monitor seeds its link index-to-name cache when it starts. Netlink link subscription delivers only changes, so without seeding every interface that predated the monitor was unknown and its address events were dropped. Since the monitor starts after boot-time config has created the configured interfaces, the dropped set was exactly the operator's own, and because a config transaction waits on the address-added event to settle, every reload that changed an address timed out and rolled back.

Renumbering inside one subnet

Address changes are make-before-break: the new address is added, then the old one removed. Inside a single subnet (10.0.0.1/24 to 10.0.0.2/24) that briefly makes the newcomer a Linux IPv4 secondary of the old address, and Linux deletes every secondary of a subnet along with its primary.

Before such a removal the netlink backend enables net.ipv4.conf.<device>.promote_secondaries, so the kernel promotes a secondary instead of flushing the subnet, logging enabled promote_secondaries when it changes the knob. If the knob cannot be set, the removal fails and names the addresses that would have been destroyed rather than silently emptying the interface.

The knob is left enabled afterwards: restoring it would re-arm the same hazard on the next removal. IPv6 has no primary/secondary distinction and is untouched, as is the VPP backend, which deletes exactly the requested address.

DHCP

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

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.

Per-interface tuning

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.

Offload and packet steering

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.

Traffic mirroring

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.

A mirror the config drops is torn down. Ze compares the mirrors the new config asks for against the mirrors the previous config installed, and removes every one that was dropped or changed before it installs the new set. A changed destination is a remove followed by an install, because tc filters are additive: installing the new destination alone would leave the old one duplicating traffic. A daemon restart starts from no previous config, so a mirror deleted from the config file while Ze was down is not reconciled away.

The mirror owns its filters, not the qdisc it shares. Mirroring attaches a tc mirred filter at priority 1 to the qdisc at handle ffff: on the source interface. That qdisc is a shared attachment point: flow-export sampling attaches its own filter at priority 100 to the same object, and both hooks, ingress and egress, hang off it. So mirror setup accepts a qdisc another subsystem created, and mirror teardown deletes its own filters and leaves the qdisc standing, empty. A teardown cannot know who created a shared qdisc. An empty qdisc carries no filter and classifies no packet, and the next mirror or sampling setup adopts it. Only the rollback of a failed setup deletes a qdisc, because it created that qdisc moments earlier and knows so.

Ze always creates clsact, never the older ingress qdisc, because clsact carries both hooks and can therefore serve a mirror with a different destination per direction. tc qdisc show on an interface that once mirrored reports a clsact qdisc with no filter on it, which is expected.

BGP integration

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.

Make-before-break migration

When you move an address from one interface or unit to another, Ze runs a five-phase migration.

  1. Add the new address.
  2. Wait for DAD on the new address.
  3. Signal BGP readiness on the new address.
  4. Update the local state.
  5. 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 30s

Tunnel interfaces

Ze 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.
ipip6 IPv4-in-IPv6 tunnel. Same kernel driver as ip6tnl, different inner protocol.
vxlan VXLAN overlay over a UDP/IPv4 underlay. Mandatory vni (1..16777215), optional port (default 4789).

All nine kinds are available on the gokrazy appliance image. The appliance kernel builds NET_IPGRE_DEMUX, NET_IPGRE, IPV6_GRE, NET_IPIP, IPV6_TUNNEL, IPV6_SIT, and VXLAN in, and the image build fails when any of the seven answers as a module instead. Earlier images could create only two of the nine kinds, so a config Ze accepted produced a device that never appeared.

A tunnel that already exists

Ze compares the tunnel config against the config this process applied before, and a netdev outlives the process that made it. So at every daemon start, and at every plugin start, a tunnel has no previous spec and the create meets a device that is already there. What holds the name decides the result:

What holds the name Result
Nothing The create runs.
A tunnel of the configured kind Ze keeps it and logs a warning. The device is not deleted and not rebuilt, so traffic crossing it is not interrupted. Its encapsulation parameters are not compared: the read-back carries the link type and no encapsulation field.
Any other device: a dummy, a bridge, a physical NIC, or a tunnel of a different kind The apply fails. Ze does not delete a device it did not create.

The last row is also what you meet after editing encapsulation while the daemon is down. There is no previous spec to compare against, so the edit does not reach the delete-and-recreate path. Ze refuses the config instead of running the old encapsulation under the new addresses. Delete the tunnel, or give the new encapsulation a new interface name.

WireGuard interfaces

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.

Route priority

The route-priority leaf on a unit controls the metric applied to default routes learned from DHCP, from a router advertisement, or from another dynamic source on that interface. Lower values mean higher priority. The pppoe-client list carries the same leaf with the same meaning, for the route a PPPoE session installs when IPCP completes.

unit main {
    ipv4 {
        dhcp { enabled true; }
    }
    route-priority 100;
}

The leaf defaults to 254. A learned default route therefore ranks below a static route and below every route a routing protocol produces. The number matches the order rib admin-distance uses for protocols: connected 0, static 10, ebgp 20, ospf 110, isis 115, ibgp 200. On link-down the metric is increased by 1024 to deprioritize the interface, and restored when the link returns.

The metric decides ownership, not only preference. Ze installs a learned default route in replace mode, and the kernel matches such a route on destination, metric, and table. It does not match on the protocol that installed it. Two default routes at different metrics are two kernel routes, and the lower metric forwards. Two default routes at the same metric are one kernel route, owned by whoever wrote it last.

Upgrading from a release that installed learned routes at metric 0

Before this release Ze installed a learned default at metric 0, where a plain static default route also lands, so the learned route replaced the operator's static default and took its gateway. Read the routes with show route default: a learned default that read metric 0 yesterday reads metric 254 today. Any policy that matches on that metric (an ip rule, a firewall mark, a monitoring check) must name 254. To keep the old metric, write route-priority 0. An explicit 0 is not the same as an absent leaf: it puts learned routes back on metric 0, with the takeover that metric carries.

A unit that writes no route-priority still leaves the IPv6 router advertisement default routes to the kernel. Writing the leaf above 0 is what makes Ze set accept_ra_defrtr=0 and install ::/0 itself when NDP neighbor events report a router.

Routes carry a protocol stamp

Every route the interface layer installs is stamped with rtm_protocol 253, which show route renders as ze-iface. This covers the DHCPv4 client, the IPv6 RA default-route manager, the PPPoE client, and the PPP NCPs. A removal matches on that protocol as well as on the destination, gateway, link, and metric, so a DHCP lease expiry or a link bounce can no longer delete an operator static route that happened to share the rest of the key. A route that survives the delete under another protocol is logged as a warning that names that protocol.

Value Name Producer
250 ze-fib The BGP/sysrib FIB kernel plugin
251 ze-static The static route plugin
252 ze-policy-route Policy routing auto-tables
253 ze-iface The interface layer: DHCP, RA, PPPoE, PPP

VPP interface backend

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.

IPv6 Router Advertisements

Ze both receives and sends Router Advertisements, and the two are separate features.

Receiving. Ze manages IPv6 default routes from advertisements another router sends. When a unit writes route-priority above 0, Ze sets accept_ra_defrtr=0, takes the default route over from the kernel, and installs ::/0 at the configured metric as NDP neighbor events report routers. See Route priority.

Sending. Ze advertises prefixes, flags, and resolvers on a LAN unit, which is the job radvd does on other systems. Hosts on the link build addresses by stateless address autoconfiguration (SLAAC), learn a default router, and learn DNS resolvers. The iface-ra plugin owns the socket, the timers, and the answers to Router Solicitations (RFC 4861).

The router-advertisement container sits inside the per-unit ipv6 container. It is Linux only and netlink only: a tree with backend vpp is rejected at config verify.

interface {
    backend netlink;
    ethernet eth0 {
        unit 0 {
            ipv6 {
                address [ 2001:db8:1::1/64 ];
                forwarding true;
                router-advertisement {
                    enabled true;
                    maximum-interval 900;
                    minimum-interval 300;
                    router-lifetime 1800;
                    hop-limit 64;
                    prefix 2001:db8:1::/64 {
                        on-link true;
                        autonomous true;
                        valid-lifetime 86400;
                        preferred-lifetime 43200;
                    }
                    rdnss {
                        server [ 2001:db8:1::53 2001:db8:1::54 ];
                        lifetime 3600;
                    }
                }
            }
        }
    }
}

Send and accept are separate

An advertising interface tells hosts to send it their off-link traffic. Set ipv6 { forwarding true; } on that unit, or the kernel drops that traffic and every host on the link loses connectivity. Leave accept-ra at 0 unless the same interface also learns from another router.

Config verify cannot catch this, because forwarding can arrive from a sysctl profile after verify runs. Ze reports the state instead: ze doctor emits doctor-iface-ra-forwarding for each advertising interface whose net.ipv6.conf.<device>.forwarding is 0.

Container leaves

Leaf Range Unit Default Meaning
enabled false Send advertisements on this unit. RFC 4861 Section 6.2.1 requires the default false, so a node never becomes a router by accident.
maximum-interval 4..1800 seconds 600 Longest wait between unsolicited advertisements (MaxRtrAdvInterval).
minimum-interval 3..1350 seconds 200 Shortest wait between unsolicited advertisements (MinRtrAdvInterval).
router-lifetime 0..9000 seconds 1800 How long hosts keep Ze in their default router list (AdvDefaultLifetime).
hop-limit 0..255 64 Value hosts put in the Hop Limit field of their outgoing packets. 0 states no value.
managed false The M flag: hosts get their addresses from DHCPv6.
other-config false The O flag: hosts get other configuration, such as DNS, from DHCPv6.
reachable-time 0..3600000 milliseconds 0 How long a host treats a neighbor as reachable after a confirmation. 0 states no value.
retransmit-timer milliseconds 0 Time between retransmitted Neighbor Solicitations on this link. 0 states no value.

Each prefix entry becomes one Prefix Information option. The list key is the prefix in CIDR notation, and SLAAC needs a 64-bit prefix.

Prefix leaf Unit Default Meaning
on-link true The L flag: hosts treat addresses in this prefix as on-link.
autonomous true The A flag: hosts build addresses from this prefix by SLAAC.
valid-lifetime seconds 2592000 How long the prefix stays valid. 30 days. 4294967295 never expires.
preferred-lifetime seconds 604800 How long addresses from the prefix stay preferred. 7 days.

Resolvers (RDNSS)

The rdnss container points a link at a resolver without a DHCPv6 server (RFC 8106). server is a leaf-list of up to 8 IPv6 addresses, and all of them share one lifetime. That leaf has no default, which is what keeps the two zero-like cases apart:

You write Ze advertises Hosts do
No lifetime leaf 3 x maximum-interval Use the resolvers, and refresh them on each advertisement.
lifetime 0 0 Stop using these resolvers.
lifetime 4294967295 4294967295 Use the resolvers, and never expire them.

Validation

The YANG ranges bound each leaf on its own. Config verify applies the cross-leaf rules of RFC 4861 that no single range can express, and each one rejects the commit.

Rule Rejected input
minimum-interval is at most 0.75 x maximum-interval minimum-interval 500 with maximum-interval 600
router-lifetime is 0, or at least maximum-interval router-lifetime 300 with maximum-interval 600
preferred-lifetime is at most valid-lifetime valid-lifetime 3600 alone, because preferred-lifetime defaults to 604800
The prefix carries no host bits prefix 2001:db8:1::1/64
The prefix is not link-local prefix fe80::/64

router-lifetime 0 is valid input: Ze then advertises its prefixes and its resolvers while it is not a default router. Ze rejects a prefix with host bits rather than masking them, because a masked prefix advertises something the operator did not write.

Send loop

One goroutine owns the socket and every timer of one sender. It joins ff02::2 to receive Router Solicitations, and it sends to ff02::1. Every advertisement leaves with Hop Limit 255, which a receiver checks.

Each unsolicited interval is picked at random between minimum-interval and maximum-interval, which keeps two routers on one link from synchronizing. The first three advertisements after a start wait 16 seconds at most, so a new router is found quickly. A solicitation draws an answer after a random wait of 500 milliseconds at most, and consecutive multicast advertisements stay 3 seconds apart, so a flood of solicitations cannot become a flood of advertisements. A sender that stops sends up to three advertisements with a Router Lifetime of 0, so each host drops Ze from its default router list at once. Nothing leaves a link that is down, and the next link-up event restarts the initial burst.

Counters

Metric Labels Counts
ze_iface_ra_sent_total interface Every advertisement put on the wire, unsolicited and solicited together.
ze_iface_ra_solicited_total interface The advertisements that answered a Router Solicitation.

A solicited advertisement increments both counters, so ze_iface_ra_sent_total stays the total.

Showing an interface

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 subcommands

Command Returns
show interface Every interface, full detail.
show interface brief One line per interface: name, state, IP, MTU.
show interface type <type> Only the interfaces of that type. An invalid type lists the valid ones.
show interface errors Only the interfaces with a non-zero Rx/Tx error or drop counter.
show interface rate [<name>] Per-second rates.
show interface name <name> detail One interface, full detail.
show interface name <name> counters One interface, counters.

Each of these has its own dispatcher entry. Earlier builds gave brief, type, errors, and rate the same entry as their parent, and the dispatcher matched the longest key first, so the parent key consumed the keyword: show interface errors answered with every interface as if each one had errors, show interface brief answered with full detail, and show interface type <t> answered with usage text.

Interface scanning

The ze interface scan command discovers all OS interfaces via netlink and reports them, useful for initial setup and troubleshooting.

PPPoE client interfaces

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 $9$-encoded on disk (required).
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

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.

Per-interface rate tracking

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 streaming

Twelve Prometheus gauges under ze_interface_* expose the rates. The web UI includes rate columns in the interface table.

What is not implemented

A few things you would expect on a more mature network OS are not in Ze. The honest list: bonding and LACP, VRF route isolation, ERSPAN, MACsec, Geneve, physical-layer tuning (speed, duplex, autoneg), and 802.1X. VXLAN and VRRP were on this list and are no longer: VXLAN is a tunnel encapsulation on both backends, and VRRP has its own page. The capability table in the in-tree interfaces features page has the full list.

See also

Adapted from main/docs/features/interfaces.md and main/docs/guide/configuration.md.

Home

About

First Steps

Configuration

Operation

Interfaces

Plugins

Plugin Development

Chaos Testing

Blueprints

Development

Reference

Clone this wiki locally