Configure VLANs, bonds, and bridges with Netplan without losing access
Build a redundant active-backup bond, carry a tagged service VLAN over it, terminate the host address on a Linux bridge, and introduce the topology through `netplan try` with automatic rollback, console recovery, and explicit switch-side evidence.
Move an Ubuntu Server 24.04 host from individual physical interfaces to a documented bond → VLAN → bridge stack while preserving the current management path until the new path is proven, validating every generated artifact, and rehearsing link failover before production workloads depend on it.
- Ubuntu Server 24.04 LTS
- Netplan 1.0, 1.1
- systemd-networkd 255
- Linux kernel 6.8
- Independent recovery Keep a tested provider, hypervisor, serial, or physical console open. A second SSH session and `netplan try` reduce risk but do not replace console access when both links, routes, or switch trunks are wrong.
Log in through the console and record the successful recovery path before changing network YAML. - Approved switch contract Both switch ports must use the intended LAG policy for active-backup bonding, permit VLAN {{vlanId}} as tagged traffic, and have loop-protection behavior documented. Do not improvise LACP on only one side.
- Separate or preserved management path Keep {{managementInterface}} and its current route untouched during the first activation, or schedule console-only work if the same path must migrate. Confirm the remote client's address and current return route.
echo "$SSH_CONNECTION"; ip route get {{remoteOperatorIp}} - Address ownership Reserve {{hostAddress}}, {{gatewayAddress}}, and DNS addresses; confirm no duplicate address exists and that the prefix belongs to VLAN {{vlanId}}.
OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.
Full guide
What you will build
- A two-link active-backup Linux bond whose MII monitor detects carrier failure without requiring LACP negotiation.
- An IEEE 802.1Q VLAN subinterface above the bond so both physical links carry the same tagged service network.
- A spanning-tree-enabled Linux bridge above the VLAN, suitable for the host address and later VM or container tap membership.
- A recovery workflow that keeps management independent, validates generated networkd units, uses timed automatic rollback, and proves link failover plus reboot persistence.
- The bond reports one active and two healthy members, with traffic continuing when either member is withdrawn in a controlled drill.
- The VLAN reports the approved tag and bond lower device; the bridge owns the address, default route metric, DNS link, and forwarding member.
- A fresh connection reaches the server through the preserved management route during activation, and the service probe uses the new bridge source.
- Netplan reports no live drift after a controlled reboot, while console rollback remains usable and documented.
Architecture
How the parts fit together
Two physical Ethernet devices remain addressless and are enslaved to an active-backup bond. The bond supplies one logical link and stable MAC behavior to an 802.1Q VLAN interface. That tagged interface becomes a port of a Linux bridge, which is the only layer in the new service stack that owns IP addresses, routes, and resolver settings. The existing management interface stays outside the new stack during first rollout. Netplan renders the declaration to systemd-networkd, while `netplan try` guards live activation with a confirmation timeout.
- The host emits an IP packet from {{hostAddress}} on {{bridgeName}} and resolves the VLAN gateway through the bridge port.
- The frame leaves the bridge through {{bondName}}.{{vlanId}}, which adds VLAN tag {{vlanId}}.
- The bond chooses its current active physical member and transmits through the corresponding switch port.
- Return frames arrive tagged on either eligible switch path, traverse the active bond member, lose the VLAN tag, enter the bridge, and reach the host or another bridge port.
- MII monitoring detects carrier failure and selects the healthy member; upstream MAC learning converges without changing the host address.
- During activation, `netplan try` keeps a rollback timer; lack of confirmation restores the prior generated state while console remains independent.
Assumptions
- The topology is an active-backup bond, not 802.3ad/LACP. LACP requires matching switch aggregation, hashing, and failure semantics and should not be substituted by changing one YAML value.
- Both physical ports reach the same Layer-2 VLAN domain and permit {{vlanId}} tagged. Native VLAN and allowed-list differences are blockers.
- {{managementInterface}} remains configured and is not one of the bond members during the first activation; if that is impossible, the maintenance becomes console-only.
- {{hostAddress}} and {{gatewayAddress}} belong to the same service prefix, are reserved, and have no duplicate owner.
- The bridge is required because the host will attach virtual endpoints or needs a stable Layer-2 aggregation point. A host with no bridge consumers could address the VLAN directly.
- The host uses Ubuntu Server's `networkd` renderer. Desktop NetworkManager and cloud-provider generated configuration require separate ownership review.
- MTU {{linkMtu}} is supported consistently by NICs, bond, VLAN, bridge, switch, gateway, and complete path; this baseline uses 1500 unless jumbo frames are proven end to end.
Key concepts
- Bond
- A Linux logical interface that combines member links. Active-backup mode transmits through one member and selects another when monitoring reports failure.
- MII monitoring
- Periodic carrier-state checking by the bonding driver. It detects local link loss but cannot prove every upstream path beyond the port.
- VLAN subinterface
- A virtual interface that represents one 802.1Q tag on a lower link and separates that broadcast domain from untagged traffic.
- Linux bridge
- A software Layer-2 switch. Member ports forward Ethernet frames; the bridge device itself is where the host attaches its Layer-3 address.
- STP
- Spanning Tree Protocol prevents forwarding loops when Layer-2 paths become redundant. Edge-only assumptions must match the physical switch design.
- Renderer
- The backend to which Netplan writes configuration. Ubuntu Server commonly uses systemd-networkd; NetworkManager semantics and ownership differ.
- netplan try
- A guarded apply that automatically rolls back unless an operator confirms within the timeout. It reduces but does not eliminate lockout risk.
- Route metric
- A preference value used when multiple candidate routes match; lower metrics are preferred. The new default remains less preferred until deliberate migration.
Before you copy
Values used in this guide
{{linkA}}First reviewed physical bond member with stable predictable interface name.
Example: enp1s0f0{{linkB}}Second reviewed physical bond member on the matching Layer-2 domain.
Example: enp1s0f1{{managementInterface}}Interface that retains the operator's existing route during first activation.
Example: ens3{{bondName}}Name of the logical active-backup bond.
Example: bond0{{vlanId}}Approved 802.1Q service VLAN identifier permitted on both switch ports.
Example: 120{{bridgeName}}Linux bridge owning service Layer-3 configuration.
Example: br120{{linkMtu}}Common MTU supported by every layer and upstream path.
Example: 1500{{hostAddress}}Reserved CIDR address assigned to the bridge.
Example: 192.0.2.20/24{{hostIpOnly}}Address portion of hostAddress used in route-source checks.
Example: 192.0.2.20{{gatewayAddress}}Default gateway reachable inside VLAN {{vlanId}}.
Example: 192.0.2.1{{dnsPrimary}}Primary resolver reachable from the service network.
Example: 192.0.2.53{{dnsSecondary}}Secondary resolver with independent availability.
Example: 192.0.2.54{{serviceProbeIp}}Stable approved address used to verify route selection through the new bridge.
Example: 192.0.2.53{{remoteOperatorIp}}Current administrator client address whose return route must remain intact.
Example: 198.51.100.35{{tryTimeout}}Seconds before Netplan automatically restores the previous live configuration.
Example: 120Security and production boundaries
- A VLAN is traffic separation, not a complete security boundary. Apply routing, bridge filtering, host firewall, switch ACL, and workload isolation according to the threat model.
- Do not attach an untrusted VM tap or container veth to {{bridgeName}} until anti-spoofing, DHCP/RA ownership, MAC limits, and egress policy are defined.
- Keep YAML mode 0600 because network files can expose internal addressing, resolver, routing, Wi-Fi credentials, or tunnels.
- A bridge can extend broadcast and neighbor-discovery attacks to the host. Monitor unexpected MAC movement, STP changes, DHCP servers, IPv6 router advertisements, and duplicate addresses.
- Active-backup improves link availability but not switch, VLAN, gateway, DNS, or control-plane availability. Document every remaining shared failure domain.
Stop before continuing if
- Stop if no independent console works or if the remote return route already uses a proposed bond member.
- Do not apply when switch ports disagree about VLANs, aggregation, native tagging, MTU, or loop protection.
- Stop if a physical NIC is owned by SR-IOV, DPDK, NetworkManager, a container runtime, another bridge/bond, or a network namespace.
- Do not confirm `netplan try` until a fresh second session proves both management return path and every new-stack checkpoint.
- Abort failover testing if MAC flapping, STP topology changes, packet storms, duplicate addresses, or application corruption appears.
- Do not reboot while `netplan status --diff`, failed units, routes, DNS, or link state remain unexplained.
verification
Map interfaces, drivers, links, routes, and current ownership
Identify every candidate NIC by predictable name, permanent MAC, driver, PCI path, carrier, MTU, current master, address, and route. The intended bond members must not already belong to a bridge, SR-IOV VF, NetworkManager connection, container stack, or another network namespace.
Why this step matters
Network migration is safe only when physical identity and current ownership are known. Predictable names can still be misunderstood after hardware replacement, and enslaving an in-use port can immediately remove its address or workload.
What to understand
Correlate predictable name, permanent MAC, PCI address, driver, firmware, carrier, speed, MTU, and switch port inventory for both links.
Inspect master relationships and all network namespaces. A device passed to a VM, SR-IOV VF, DPDK process, or container cannot also become a normal bond member.
Save route and address output with timestamps. The lack of an address does not prove the interface is unused at Layer 2.
System changes
- No persistent change; reads kernel link, address, route, driver, and networkd state.
Syntax explained
ip -details link- Shows master, VLAN, bond, bridge, MTU, flags, and link-layer attributes.
ethtool -i- Reports driver, version, firmware, and PCI bus identity.
ethtool -P- Reports the permanent hardware address rather than a current inherited MAC.
ip route show table all- Includes policy-routing tables beyond the main table.
Values stay on this page and are never sent or saved.
ip -brief link; ip -brief address; ip -details link show; ip route show table all; networkctl list --no-pager; sudo ethtool -i {{linkA}}; sudo ethtool -P {{linkA}}; sudo ethtool -i {{linkB}}; sudo ethtool -P {{linkB}}lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP> ens3 UP 52:54:00:11:22:33 <BROADCAST,MULTICAST,UP,LOWER_UP> enp1s0f0 UP 3c:fd:fe:aa:10:01 <BROADCAST,MULTICAST,UP,LOWER_UP> enp1s0f1 UP 3c:fd:fe:aa:10:02 <BROADCAST,MULTICAST,UP,LOWER_UP> default via 198.51.100.1 dev ens3 proto static 2: enp1s0f0 ether 3c:fd:fe:aa:10:01 (not set) 3: enp1s0f1 ether 3c:fd:fe:aa:10:02 (not set) driver: ixgbe bus-info: 0000:01:00.0 Permanent address: 3c:fd:fe:aa:10:01
Checkpoint: Approve physical members
Continue when{{linkA}} and {{linkB}} map to intended switch ports, use supported drivers/MTU, have carrier, and have no conflicting owner.
Stop whenAny identity, master, namespace, or workload ownership is ambiguous.
If this step fails
A candidate interface does not appear in the default namespace.
Likely causeIt is passed through, renamed, disabled in firmware, or moved to another network namespace.
lspci -nnk | grep -A3 -i ethernetip netns listsudo find /sys/class/net -maxdepth 1 -type l -printf '%f -> %l\n'
ResolutionRestore documented ownership and naming before Netplan configuration; do not create YAML for a guessed device.
Security notes
- Permanent MACs, PCI inventory, and internal routes are sensitive asset data; restrict the captured baseline.
Alternatives
- Use signed hardware inventory and switch LLDP data if locally available, while corroborating with kernel names.
Stop conditions
- No change begins with an unowned interface.
verification
Capture the effective Netplan and remote return path
Record merged Netplan, renderer, generated networkd files, DNS state, neighbor table, and the exact route back to the operator. This is the comparison and rollback baseline, not a screenshot of one YAML file.
Why this step matters
Netplan merges files from multiple locations and renders backend state. Capturing the merged declaration, live state, resolver, and exact SSH return path provides a trustworthy recovery target.
What to understand
`netplan get` shows the merged logical configuration, while `netplan status` compares declared and live state.
`ip route get` with the operator address identifies the actual egress, source, and gateway that must remain untouched.
Keep the original SSH connection tuple so a fresh-session test proves the same management contract rather than an unrelated path.
System changes
- No persistent change; reads Netplan, networkd, resolver, route, neighbor, and session state.
Syntax explained
netplan get- Displays merged YAML from Netplan configuration sources.
netplan status --all- Shows all Netplan-managed interfaces and their live state.
ip route get- Asks the kernel which route and source it would use for one destination.
$SSH_CONNECTION- Records client/server addresses and ports for the current SSH session.
Values stay on this page and are never sent or saved.
sudo netplan get; sudo netplan status --all; systemctl is-active systemd-networkd; resolvectl status --no-pager; ip route get {{remoteOperatorIp}}; ip neigh show; echo "$SSH_CONNECTION"network:
version: 2
renderer: networkd
ethernets:
ens3:
addresses:
- 198.51.100.20/24
routes:
- to: default
via: 198.51.100.1
active
198.51.100.35 via 198.51.100.1 dev ens3 src 198.51.100.20 uid 1000
198.51.100.35 51224 198.51.100.20 22Checkpoint: Protect the return path
Continue when{{managementInterface}} owns the route to {{remoteOperatorIp}}, its configuration is captured, and it is not a proposed bond member.
Stop whenThe current session depends on {{linkA}}, {{linkB}}, or a route that the new YAML changes.
If this step fails
Netplan status already reports drift.
Likely causeA runtime command, cloud agent, NetworkManager, or unmanaged backend file changed live state.
sudo netplan status --diffsudo netplan getsudo find /run/systemd/network /etc/systemd/network -type f -maxdepth 2 -print
ResolutionResolve ownership and converge the existing network before layering a topology migration.
Security notes
- Redact public and management addresses before sharing output externally.
Alternatives
- Use a configuration-management snapshot that includes merged source and generated backend state.
Stop conditions
- Existing unexplained drift blocks the new change.
decision
Verify both physical switch paths before bonding
Have the network operator confirm port identity, access/trunk mode, allowed VLANs, native VLAN, spanning-tree edge policy, error counters, and whether an aggregation group exists. For active-backup, both member ports must reach the same Layer-2 domain without requiring LACP negotiation.
Why this step matters
Linux cannot compensate for an untagged trunk, mismatched VLAN list, disabled port, or unexpected LACP group. Proving both physical paths first prevents host debugging from masking a switch contract error.
What to understand
Active-backup expects both ports to carry the same Layer-2 domain independently. A switch-side LAG may be unnecessary or vendor-specific; its policy must match the approved design.
Zero or stable error counters and matching speed/duplex establish a usable baseline before failover generates new counters.
Document STP edge behavior and port-security MAC movement because the bond may move its MAC between ports.
System changes
- No host change; reads carrier and driver counters while the network operator verifies switch configuration.
Syntax explained
ethtool interface- Reports negotiated speed, duplex, and carrier.
ethtool -S- Reads driver-specific NIC counters used to detect physical errors or drops.
Values stay on this page and are never sent or saved.
sudo ethtool {{linkA}} | grep -E 'Speed:|Duplex:|Link detected:'; sudo ethtool -S {{linkA}} | grep -E 'rx.*error|tx.*error|drop' | head -n 12; sudo ethtool {{linkB}} | grep -E 'Speed:|Duplex:|Link detected:'; sudo ethtool -S {{linkB}} | grep -E 'rx.*error|tx.*error|drop' | head -n 12Speed: 10000Mb/s
Duplex: Full
Link detected: yes
rx_errors: 0
tx_errors: 0
Speed: 10000Mb/s
Duplex: Full
Link detected: yes
rx_errors: 0
tx_errors: 0Checkpoint: Approve both switch paths
Continue whenBoth links negotiate the intended speed/duplex, counters are clean, VLAN {{vlanId}} is tagged, and switch loop/MAC policy supports failover.
Stop whenAny port, VLAN, MTU, aggregation, native VLAN, or STP setting differs.
If this step fails
One member has carrier but rapidly increasing CRC errors.
Likely causeCabling, optics, FEC, speed, or switch port quality is poor.
sudo ethtool -S enp1s0f1 | grep -iE 'crc|error|drop'sudo ethtool enp1s0f1
ResolutionRepair the physical path and reset/record counters before it joins the bond; redundancy built from a bad link is not redundancy.
Security notes
- Switch screenshots and port mappings expose physical topology; store them with network operations records.
Alternatives
- Use approved streaming switch telemetry plus host NIC counters.
Stop conditions
- Do not bond a physically unhealthy or policy-mismatched port.
command
Create a protected Netplan recovery bundle
Archive all administrator Netplan files and generated networkd state before editing. Record hashes and current routes in a root-only directory so console rollback restores the complete input set rather than one guessed file.
Why this step matters
A directory-level backup preserves every merged administrator input and generated artifact needed to understand rollback, avoiding the common mistake of restoring only the newly edited file.
What to understand
Copy with metadata into mode 0700 root storage and record hashes before any edit.
Generated files are evidence, not the primary rollback input; Netplan should regenerate them from restored YAML.
Capture routes separately because they identify the actual pre-change operational behavior.
System changes
- Creates `/root/netplan-before-wyd302` containing protected configuration, generated-state evidence, routes, and hashes.
Syntax explained
install -d -m 0700- Creates a root-only recovery directory.
cp --archive- Preserves ownership, mode, timestamps, symlinks, and content.
sha256sum- Fingerprints pre-change YAML for recovery verification.
sudo install -d -m 0700 /root/netplan-before-wyd302 && sudo cp --archive /etc/netplan/. /root/netplan-before-wyd302/etc-netplan/ && sudo cp --archive /run/systemd/network /root/netplan-before-wyd302/run-systemd-network && sudo ip route show table all > /root/netplan-before-wyd302/routes.txt && sudo sha256sum /etc/netplan/*.yaml | sudo tee /root/netplan-before-wyd302/sha256.txt/etc/netplan/50-cloud-init.yaml: copied /etc/netplan/99-management.yaml: copied 8d76e390d19ff7a93aac0f4e11fc6d971e1ce98ac331f0bb324046555154d620 /etc/netplan/50-cloud-init.yaml 0dafb1b35c98358c3c1bbb8994fbf2ad2daa215e5272cd034db08953bd80cfbd /etc/netplan/99-management.yaml
Checkpoint: Prove recoverable input
sudo find /root/netplan-before-wyd302 -maxdepth 3 -type f -ls; sudo cat /root/netplan-before-wyd302/sha256.txtContinue whenEvery current YAML exists in the bundle with matching hash and root-only access.
Stop whenA source file, metadata, space, or checksum is missing.
If this step fails
The destination already contains an older recovery bundle.
Likely causeA previous network change was incomplete or reused the fixed path.
sudo stat /root/netplan-before-wyd302sudo find /root/netplan-before-wyd302 -maxdepth 3 -type f -ls
ResolutionArchive the older evidence under its change identifier and create a fresh verified bundle; never overwrite unknown recovery state.
Security notes
- The bundle contains internal topology and must remain root-only and excluded from general backups unless encrypted.
Alternatives
- Use version-controlled, encrypted configuration management plus a locally available console restore artifact.
Stop conditions
- No live change without a complete recovery bundle.
config
Declare the bond, tagged VLAN, and bridge
Leave the existing management interface in its current file. Add two addressless bond members, an active-backup bond with MII monitoring and a named primary, a VLAN above the bond, and a bridge that owns the service address, route, DNS, STP, and MTU.
Why this step matters
A single declarative hierarchy makes interface ownership unambiguous: physical ports belong to the bond, the VLAN belongs to the bond, and Layer-3 settings belong only to the bridge.
What to understand
Active-backup with 100 ms MII monitoring is conservative and switch-independent. The primary preference is operational policy, not a health guarantee.
The service default route uses metric 200 so the preserved management default can remain preferred during first activation.
STP and forward delay protect future Layer-2 expansion; confirm the value with switch convergence requirements.
Use the same MTU at all stack layers. VLAN tagging does not justify a larger host MTU unless the physical path supports it.
System changes
- Creates persistent Netplan policy that will re-parent both NICs, create bond/VLAN/bridge devices, and add service Layer-3 configuration when applied.
Syntax explained
mode: active-backup- Transmits through one member and selects another when link monitoring marks it unavailable.
mii-monitor-interval: 100- Checks member carrier every 100 milliseconds.
id: {{vlanId}} / link: {{bondName}}- Creates the approved 802.1Q tag above the logical bond.
interfaces: [bond.vlan]- Makes the VLAN device a bridge port.
metric: 200- Keeps this default route less preferred than a lower-metric management route during migration.
stp: true- Enables Linux bridge spanning-tree participation.
/etc/netplan/60-oneliners-service-fabric.yamlValues stay on this page and are never sent or saved.
network:
version: 2
renderer: networkd
ethernets:
{{linkA}}:
dhcp4: false
dhcp6: false
optional: true
{{linkB}}:
dhcp4: false
dhcp6: false
optional: true
bonds:
{{bondName}}:
interfaces: [{{linkA}}, {{linkB}}]
mtu: {{linkMtu}}
parameters:
mode: active-backup
primary: {{linkA}}
mii-monitor-interval: 100
vlans:
{{bondName}}.{{vlanId}}:
id: {{vlanId}}
link: {{bondName}}
mtu: {{linkMtu}}
bridges:
{{bridgeName}}:
interfaces: [{{bondName}}.{{vlanId}}]
addresses: [{{hostAddress}}]
routes:
- to: default
via: {{gatewayAddress}}
metric: 200
nameservers:
addresses: [{{dnsPrimary}}, {{dnsSecondary}}]
parameters:
stp: true
forward-delay: 4
mtu: {{linkMtu}}network:
version: 2
renderer: networkd
ethernets:
enp1s0f0: {dhcp4: false, dhcp6: false, optional: true}
enp1s0f1: {dhcp4: false, dhcp6: false, optional: true}
bonds:
bond0:
interfaces: [enp1s0f0, enp1s0f1]
mtu: 1500
parameters:
mode: active-backup
primary: enp1s0f0
mii-monitor-interval: 100
vlans:
bond0.120:
id: 120
link: bond0
mtu: 1500
bridges:
br120:
interfaces: [bond0.120]
addresses: [192.0.2.20/24]
routes: [{to: default, via: 192.0.2.1, metric: 200}]
nameservers: {addresses: [192.0.2.53, 192.0.2.54]}
parameters: {stp: true, forward-delay: 4}
mtu: 1500Checkpoint: Peer-review the hierarchy
sudo netplan getContinue whenManagement remains untouched; members have no addresses; bond, VLAN, and bridge references form one acyclic hierarchy; only bridge owns service Layer 3.
Stop whenAn address appears on a member, an interface is referenced twice, or the default route supersedes management unexpectedly.
If this step fails
Netplan reports that an interface is already assigned to another device.
Likely causeAnother YAML file also enslaves the NIC or cloud-generated configuration owns it.
sudo netplan getsudo grep -R --line-number 'enp1s0f0\|enp1s0f1' /etc/netplan /lib/netplan /run/netplan 2>/dev/null
ResolutionChoose one authoritative declaration and remove conflicting ownership through an explicit migration, not file-order guessing.
Security notes
- Do not include switch credentials or secret DNS tokens in YAML.
Alternatives
- Create native systemd-networkd units only when Netplan cannot express a supported requirement and ownership is documented.
Stop conditions
- A duplicate interface owner or management-route change blocks generation.
verification
Validate YAML and inspect generated networkd units
Set restrictive YAML permissions, run Netplan generation with debug, and inspect the generated `.network`, `.netdev`, and `.link` files. Generation must succeed before any live apply, and the bridge alone should own the service Layer-3 address.
Why this step matters
Offline rendering validates YAML and exposes the exact backend units before the kernel network changes, catching indentation, unsupported keys, duplicate routes, and wrong ownership at the safest point.
What to understand
Mode 0600 removes Netplan's warning about overly permissive configuration and protects internal details.
`netplan --debug generate` parses the merged configuration and writes backend files without applying them.
Inspect address placement, bond parameters, VLAN ID/lower link, bridge membership, route metric, and resolver output in generated units.
System changes
- Writes generated backend files under `/run/systemd/network`; live links and routes remain unchanged.
Syntax explained
chmod 0600- Restricts Netplan input to root.
--debug generate- Parses and renders all configuration while printing detailed decisions without applying live state.
find ... -exec sed- Enumerates and displays generated units for review.
sudo chmod 0600 /etc/netplan/60-oneliners-service-fabric.yaml && sudo netplan --debug generate && sudo find /run/systemd/network -maxdepth 1 -type f -name '10-netplan-*' -print -exec sed -n '1,160p' {} \;** (generate:4811): DEBUG: 09:14:22.347: starting new processing pass ** (generate:4811): DEBUG: 09:14:22.349: enp1s0f0: adding as member of bond0 ** (generate:4811): DEBUG: 09:14:22.349: bond0.120: adding as member of bridge br120 /run/systemd/network/10-netplan-bond0.netdev [NetDev] Name=bond0 Kind=bond /run/systemd/network/10-netplan-br120.network [Match] Name=br120 [Network] Address=192.0.2.20/24
Checkpoint: Approve generated backend
Continue whenGeneration exits zero; units show two bond members, tag {{vlanId}}, bridge membership, bridge-only address, route metric, and DNS.
Stop whenAny warning, unknown key, unexpected unit, address owner, route, or renderer appears.
If this step fails
Generation accepts YAML but emits the wrong renderer.
Likely causeAnother merged file sets NetworkManager or a device-specific renderer.
sudo netplan get network.renderersudo netplan --debug generatesudo find /run/NetworkManager/system-connections /run/systemd/network -type f -maxdepth 2 -print
ResolutionResolve renderer ownership and regenerate for the supported backend before live testing.
Security notes
- Generated files may repeat internal addresses; restrict diagnostic bundles.
Alternatives
- Render and inspect in an identical staging VM, then repeat generation on the host.
Stop conditions
- No live apply after a nonzero generation or unreviewed warning.
command
Apply through netplan try with automatic rollback
Use the recovery console or a persistent terminal multiplexer, keep the original SSH session open, and start `netplan try` with a short timeout. Do not confirm until a second independent session proves the old management path and the new service path.
Why this step matters
Timed application creates a defined escape from remote lockout. Keeping console and the original session open makes automatic rollback observable and prevents confirmation based only on local link state.
What to understand
Run from console or a stable multiplexer; the initiating terminal owns the confirmation prompt.
Open a fresh remote session after application. Existing TCP sessions can survive route mistakes temporarily and are not proof of new connection reachability.
Do not press Enter until stack, route, DNS, remote access, and drift checks all pass. Timeout should be long enough for checks but short enough for recovery.
System changes
- Temporarily applies generated network changes; confirmation makes them live, while timeout attempts automatic restoration.
Syntax explained
netplan try- Applies configuration under a confirmation guard and rolls back when unconfirmed.
--timeout {{tryTimeout}}- Sets the automatic rollback interval in seconds.
Values stay on this page and are never sent or saved.
sudo netplan try --timeout {{tryTimeout}}Do you want to keep these settings? Press ENTER before the timeout to accept the new configuration Changes will revert in 120 seconds Configuration accepted.
Checkpoint: Keep recovery alive
ip route get {{remoteOperatorIp}}; ss -tn state established '( sport = :22 )'Continue whenConsole remains responsive, original and fresh SSH sessions work through {{managementInterface}}, and rollback countdown is visible.
Stop whenAny management session, route, console, or backend service becomes unstable.
If this step fails
The SSH session freezes immediately.
Likely causeThe management interface or route was re-parented, address moved, or default route preference changed.
ip route get 198.51.100.35networkctl list --no-pagerjournalctl -u systemd-networkd --since '-5 minutes' --no-pager
ResolutionDo not confirm. Use console to observe automatic rollback; if it fails, restore the recovery bundle and apply from console.
Security notes
- Do not extend the timeout repeatedly to debug an unknown live state; roll back and investigate offline.
Alternatives
- Use console-only `netplan apply` in an isolated maintenance environment when `try` is unsupported, with a pre-scheduled independent rollback.
Stop conditions
- Loss of one required management path ends the trial.
verification
Prove bond, VLAN, bridge, routes, and DNS before confirmation
From console and a fresh remote session, verify the bond's active slave and MII state, VLAN ID and lower device, bridge membership and STP state, exact source route, resolver link, gateway reachability, and Netplan drift. Confirm only when every layer agrees.
Why this step matters
Layered verification proves that a locally up bridge is backed by the intended physical redundancy, tag, route, gateway, and resolver rather than an incomplete or accidentally reachable topology.
What to understand
Bond `/proc` state is authoritative for mode, active member, MII, and failure counts.
`ip -details` and `bridge` expose VLAN and port hierarchy; route-get with an explicit source proves Layer-3 selection.
`netplan status --diff` closes the declaration/live loop, while a fresh remote session proves connection establishment.
System changes
- No intended persistent change; reads live link, bridge, route, resolver, and Netplan state and sends three gateway probes.
Syntax explained
/proc/net/bonding- Shows kernel bonding mode, current active member, MII state, and failure counters.
ip -details link- Shows VLAN ID, lower device, MTU, and flags.
bridge link/vlan- Shows bridge ports, forwarding state, and VLAN filtering view.
netplan status --diff- Reports differences between declared Netplan and live system state.
Values stay on this page and are never sent or saved.
cat /proc/net/bonding/{{bondName}}; ip -details link show {{bondName}}.{{vlanId}}; bridge link show master {{bridgeName}}; bridge vlan show; ip -brief address show {{bridgeName}}; ip route get {{serviceProbeIp}} from {{hostIpOnly}}; resolvectl status {{bridgeName}} --no-pager; ping -c 3 {{gatewayAddress}}; sudo netplan status --diffBonding Mode: fault-tolerance (active-backup) Primary Slave: enp1s0f0 (primary_reselect always) Currently Active Slave: enp1s0f0 MII Status: up 7: bond0.120@bond0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 vlan protocol 802.1Q id 120 9: bond0.120 state forwarding priority 32 cost 100 br120 UP 192.0.2.20/24 192.0.2.53 via 192.0.2.1 dev br120 src 192.0.2.20 Difference: none
Checkpoint: Confirm all layers before accepting
Continue whenTwo healthy members, correct tag and lower link, forwarding bridge port, bridge address/route/DNS, gateway response, new SSH session, and no drift.
Stop whenAny layer is merely assumed or differs from the approved plan.
If this step fails
DNS queries fail while gateway ping succeeds.
Likely causeResolver addresses, route source, firewall, split-DNS domain, or systemd-resolved link ownership is wrong.
resolvectl status br120 --no-pagerresolvectl query example.netip route get 192.0.2.53 from 192.0.2.20
ResolutionCorrect bridge nameserver/link routing and prove both resolvers independently before confirmation.
Security notes
- Use approved gateway and resolver probes; do not scan the VLAN.
Alternatives
- Use application-layer health probes in addition to, not instead of, layer checks.
Stop conditions
- Do not confirm based on ping alone.
decision
Rehearse one bond-member failure
In a canary or approved maintenance window, disable one switch port or physically disconnect one bond member at a time. Observe active-slave transition, packet loss, route continuity, neighbor state, and application probe latency; then restore the link and repeat for the other member.
Why this step matters
Redundancy exists only after a controlled member failure proves carrier detection, active selection, upstream MAC convergence, route continuity, and acceptable application loss.
What to understand
Withdraw one physical path at the switch or cable, never with an unreviewed software command that may affect both members.
Run a low-rate gateway and application probe while watching active member and failure counters. Record loss and convergence time.
Restore the first link and stable state before testing the second. Confirm no MAC flapping or switch security event occurred.
System changes
- Temporarily removes one physical network path and causes the bond to select its backup member.
Syntax explained
Currently Active Slave- Identifies the physical member transmitting for active-backup mode.
MII Status- Shows bond and member carrier-monitor result.
watch -n 0.5- Refreshes a narrow status view twice per second without changing state.
Values stay on this page and are never sent or saved.
watch -n 0.5 "grep -E 'Currently Active Slave|MII Status|Slave Interface' /proc/net/bonding/{{bondName}}"Currently Active Slave: enp1s0f1 MII Status: up Slave Interface: enp1s0f0 MII Status: down Slave Interface: enp1s0f1 MII Status: up
Checkpoint: Accept measured failover
grep -E 'Currently Active Slave|MII Status|Link Failure Count' /proc/net/bonding/{{bondName}}Continue whenEach single-member withdrawal causes one bounded transition, service remains within loss objective, and restored members return healthy.
Stop whenBoth paths fall, convergence exceeds objective, counters surge, or switch reports loop/MAC violations.
If this step fails
Traffic works when link A fails but not when link B fails.
Likely causeThe second switch path lacks VLAN {{vlanId}}, has wrong native mode, MTU, STP, gateway reachability, or physical quality.
cat /proc/net/bonding/bond0sudo tcpdump -eni enp1s0f1 vlan 120 and arpsudo ethtool -S enp1s0f1 | grep -iE 'error|drop'
ResolutionRestore the known-good member, correct the second end-to-end switch path, and repeat the isolated drill before declaring redundancy.
Security notes
- Coordinate port actions with network operations to avoid triggering automated containment or affecting another host.
Alternatives
- Use a lab switch and traffic generator first, then perform a shorter production member withdrawal.
Stop conditions
- Any unbounded or asymmetric failure ends testing and requires rollback to one known-good path.
verification
Prove persistence through a controlled reboot
After the live stack and failover drill pass, schedule one controlled reboot with console open. Verify the same interface hierarchy, active slave, routes, DNS, Netplan drift, and service probes after boot before closing the change.
Why this step matters
A live apply can succeed while boot ordering, predictable names, switch convergence, or generator precedence fails after restart; one controlled reboot is therefore part of acceptance.
What to understand
Keep console attached and record boot start, failed units, networkd state, bond hierarchy, route, DNS, drift, and application checks.
Compare active member and permanent MAC assumptions with the pre-reboot state. Active-backup may select a different healthy member, which is acceptable if policy allows.
Do not close the change until fresh remote sessions and service probes work after boot.
System changes
- Reboots the host, recreating the full interface hierarchy from persistent Netplan configuration.
Syntax explained
networkctl status- Shows networkd operational/setup state and generated ownership for selected interfaces.
netplan status --diff- Detects post-boot divergence from declared state.
systemctl --failed- Shows units that failed during or after boot.
Values stay on this page and are never sent or saved.
uptime -s; systemctl --failed --no-pager; networkctl status {{bondName}} {{bondName}}.{{vlanId}} {{bridgeName}} --no-pager; ip route get {{serviceProbeIp}}; resolvectl status {{bridgeName}} --no-pager; sudo netplan status --diff2026-07-28 10:04:13
UNIT LOAD ACTIVE SUB DESCRIPTION
0 loaded units listed.
● 5: bond0
State: enslaved (configured)
● 7: bond0.120
State: enslaved (configured)
● 8: br120
State: routable (configured)
192.0.2.53 via 192.0.2.1 dev br120 src 192.0.2.20
Difference: noneCheckpoint: Close on post-boot convergence
Continue whenNo unexplained failed unit, hierarchy is configured/routable, routes and DNS match, fresh access works, and Netplan drift is empty.
Stop whenConsole, names, links, routes, DNS, services, or drift differ after boot.
If this step fails
A bond member has a different name after reboot.
Likely causeHardware replacement, firmware, unpredictable naming, or matching by name alone changed identity.
ip -brief linkudevadm info /sys/class/net/enp1s0f0sudo ethtool -P enp1s0f0
ResolutionUse console to restore the previous topology, update inventory and stable Netplan match/set-name policy, then repeat generation and try.
Security notes
- Do not disable predictable naming globally as an outage shortcut.
Alternatives
- Reboot a faithful clone first, but still perform one production reboot before depending on persistence.
Stop conditions
- No acceptance while the configuration works only in current runtime state.
Finish line
Verification checklist
sudo netplan status --diffNetplan reports no difference between declared and live state for the two NICs, bond, VLAN, bridge, addresses, routes, and DNS.grep -E 'Bonding Mode|Currently Active Slave|MII Status|Slave Interface' /proc/net/bonding/{{bondName}}Mode is active-backup, bond MII is up, exactly one slave is active, and both restored member links report up.ip route get {{serviceProbeIp}} from {{hostIpOnly}} && ping -c 3 {{gatewayAddress}}The source route leaves through {{bridgeName}} using {{hostIpOnly}}, and all three gateway probes return without loss.Recovery guidance
Common problems and safe checks
Both bond members show up, but the bond reports no active slave.
Likely causeCarrier is down, switch ports are disabled/mispatched, bond members remained owned elsewhere, or monitoring cannot see a valid link.
ip -details link show enp1s0f0 enp1s0f1 bond0cat /proc/net/bonding/bond0sudo ethtool enp1s0f0networkctl status enp1s0f0 enp1s0f1 --no-pager
ResolutionRestore one correctly patched and switch-approved physical path, remove conflicting ownership, and require MII up before continuing. Do not force the bond carrier state.
The bond is up, but the VLAN gateway cannot be reached.
Likely causeVLAN {{vlanId}} is absent from one or both trunks, native/tagged expectations differ, or the VLAN was attached below the wrong logical device.
ip -details link show bond0.120sudo tcpdump -eni bond0 vlan 120 and arpbridge vlan showip neigh show dev br120
ResolutionAlign the switch allowed/tagged VLAN and verify the Netplan VLAN link is the bond. Capture only ARP and tag metadata long enough to prove direction.
The bridge has the address, but replies leave through the management interface.
Likely causeRoute metrics, policy rules, source-address selection, or a duplicate default route prefer the old path.
ip rule showip route show table allip route get 192.0.2.53 from 192.0.2.20sudo netplan status --diff
ResolutionCorrect the explicit route and metric or add reviewed policy routing. Keep management preferred until service routing is separately proven.
Failover changes active slave but traffic pauses for tens of seconds.
Likely causeUpstream MAC learning, switch port transition, STP, gratuitous ARP behavior, or neighbor caches converge slowly.
cat /proc/net/bonding/bond0bridge link showip monitor link neigh routesudo tcpdump -eni bond0 arp or icmp
ResolutionReview switch edge/STP and MAC-move policy, bonding notification behavior, and measured application tolerance. Do not hide long convergence by increasing timeouts.
`netplan try` rolls back even though local console probes worked.
Likely causeThe confirmation was not entered in the initiating terminal, the session disconnected, or a backend limitation prevented confirmation.
journalctl -u systemd-networkd --since '-10 minutes' --no-pagersudo netplan --debug generateip route get 198.51.100.35
ResolutionTreat rollback as successful protection, correct the remote path or terminal workflow, and repeat from console or a stable multiplexer.
Reference
Frequently asked questions
Why put the VLAN above the bond?
The bond should choose a physical member first, while the VLAN provides one consistent tagged interface above that logical link. The kernel bonding documentation also describes VLAN support above bonds.
Why put the address on the bridge rather than its VLAN port?
The bridge is the host's attachment to that Layer-2 domain. Member ports remain Layer-2 only; assigning the address to a member creates confusing ownership and reachability.
Does active-backup need LACP?
No. It uses one transmitting member and carrier monitoring. LACP is a different mode requiring matching switch aggregation and should be planned independently.
Is `netplan try` enough to protect remote access?
No. It provides timed rollback, but console remains necessary for switch mistakes, backend failures, simultaneous route loss, or a reboot after an unconfirmed state.
Should STP always be enabled?
A bridge that may gain redundant ports should have a deliberate loop-prevention design. In a single-port bridge, STP adds a small transition but preserves safer future behavior; match it to switch policy.
Recovery
Rollback
Rollback relies first on `netplan try` timing out without confirmation. Manual console rollback restores the complete pre-change `/etc/netplan` input set, regenerates backend files, and reapplies the previous topology. It cannot undo switch changes, duplicate-address effects, or application traffic sent over the wrong VLAN.
- If remote access or any checkpoint fails during `netplan try`, do not confirm; wait for automatic rollback and verify the original route from console.
- For manual recovery, copy `/root/netplan-before-wyd302/etc-netplan/.` back to `/etc/netplan/`, preserve mode 0600, and run `sudo netplan --debug generate` before applying.
- Run `sudo netplan apply` from console, verify the route to {{remoteOperatorIp}}, then remove or reverse the switch trunk/LAG changes only after host traffic has returned to the original interfaces.
- Preserve `journalctl -u systemd-networkd`, generated files, switch counters, and the failed YAML for analysis; do not repeatedly apply variants over an unknown live topology.
Evidence