BGP Active-Active Dual-Homed Home Enterprise
Overview
This document covers end-to-end design, procurement, physical prerequisites, and production VyOS configuration for the Domus Digitalis home enterprise BGP network.
| Goal | Implementation |
|---|---|
No single point of failure |
Two physical ISP circuits, two independent BGP upstreams, two VyOS nodes. Any single failure leaves at least one forwarding path intact. |
Active-active forwarding |
Both VyOS nodes forward live traffic simultaneously via split VRRP mastership and AS-path prepend traffic engineering. |
Provider-independent IPv6 |
PI /48 registered under your ASN. Permanent, portable, independent of any LIR’s business continuity. |
Dual-stack clients |
BGP carries IPv6 PI space. NAT44 on VyOS provides IPv4 outbound for legacy devices. DNS64/NAT64 reduces IPv4 dependency for capable clients. |
PE handoff survivability |
BFD with per-ISP tuned timers. Aggressive BGP hold timers. conntrack-sync preserves sessions across reconvergence. |
Operational hygiene |
RPKI ROA, IRR objects, graceful shutdown, VRF-based WAN separation instead of policy routing tables. |
Phase 0: Physical Prerequisites
Verify these before spending any money on procurement.
0.1 NIC Availability — Supermicro E300-9D
Both kvm-01 and kvm-02 have 8x RJ45 10GbE ports (eno1-eno8). Current usage:
| Port | State | Bridge | Purpose |
|---|---|---|---|
eno7 |
UP (10GbE) |
br-wan |
ISP-A modem (existing WAN) |
eno8 |
UP (10GbE) |
br-mgmt |
LAN trunk to switch |
eno1-6 |
DOWN |
— |
6 ports available |
No additional hardware required. Use eno1 for ISP-B (T-Mobile gateway).
# Verify port status on each hypervisor
for port in eno{1..8}; do
state=$(cat /sys/class/net/$port/operstate 2>/dev/null || echo "missing")
speed=$(cat /sys/class/net/$port/speed 2>/dev/null || echo "?")
master=$(ip link show $port 2>/dev/null | awk -F'master ' '{print $2}' | awk '{print $1}')
printf "%-6s %-6s %5sMbps %s\n" "$port" "$state" "$speed" "${master:-[none]}"
done
0.2 T-Mobile 5G Coverage
Verify 5G Home Internet is available at your Pasadena address before ordering:
-
Coverage check: t-mobile.com/home-internet
-
Order online — no contract, no installation fee (~$50/mo)
-
Gateway device ships via mail, self-install
-
Note: T-Mobile 5G Home Internet is behind CGNAT — outbound WireGuard works fine (UDP + persistent keepalive), inbound services must route via your BGP-announced PI /48
0.3 ISP-A Modem Configuration
Your wired ISP modem must be in bridge mode or have a DMZ host setting pointing to the Supermicro WAN interface. This ensures VyOS receives the public WAN IP directly rather than double-NAT.
# Verify after bridge mode: VyOS eth0 should show public IP
show interfaces ethernet eth0
# Address should be a public IPv4, not 192.168.x.x
Physical Architecture
Last-Mile Circuits
| Circuit | Provider | Cost | Hypervisor bridge |
|---|---|---|---|
ISP-A |
Wired cable or fiber (existing) |
~$50–80/mo |
br-wan → eno7 (existing) |
ISP-B |
T-Mobile 5G Home Internet |
~$50/mo, no contract |
br-ispb → eno1 (new) |
|
Why T-Mobile 5G for ISP-B
Completely separate physical infrastructure — cellular towers, different backbone, independent failure domain. A fiber cut, cable node outage, or DSLAM failure does not affect the cellular path. This is the cheapest genuine physical last-mile redundancy available in the US (~$50/mo, no contract). T-Mobile CGNAT does not impact outbound WireGuard tunnels — UDP keepalives maintain the session through NAT state. |
Full Topology
[ISP-A modem/ONT] [T-Mobile 5G gateway]
| |
[eno7] [eno1]
[br-wan] [br-ispb]
| \ / |
| \ / |
[vyos-01] [vyos-02]
eth0=WAN-A primary eth0=LAN (SWAPPED - needs fix)
eth1=LAN eth1=WAN-A
| |
VRF WAN-A (table 100) VRF WAN-B (table 200)
wg0 → iFog Fremont wg0 → iFog Fremont
wg1 → ROUTE64 wg1 → ROUTE64
| |
+-------------+ +-------------+
| |
[eth3 HA link]
10.50.99.0/30
conntrack-sync
|
[eth2 internal trunk]
VRRP split-master
dual-stack downstream
|
Current State (Pre-Migration)
The VyOS nodes currently have only 2 interfaces each, and vyos-02 has interfaces flipped (eth0=LAN, eth1=WAN instead of eth0=WAN, eth1=LAN). Phase 1.5 below documents the zero-downtime VRRP migration to add eth2 (ISP-B) and eth3 (HA-sync) to each VM while fixing the interface order on vyos-02. |
KVM Bridge Layout
| Bridge | Physical interface | Purpose |
|---|---|---|
br-wan |
eno7 → ISP-A modem (existing) |
WAN-A uplink. VyOS eth0. |
br-ispb |
eno1 → T-Mobile gateway (new) |
WAN-B uplink. VyOS eth1 (after migration). |
br-mgmt |
eno8 → LAN trunk to switch (existing) |
Downstream VLANs. VRRP VIPs. Dual-stack. |
br-ha |
Internal crosslink (no physical NIC) |
conntrack-sync + VRRP peer comms only. |
# Verify existing bridges on hypervisor
bridge link show
# Create new br-ispb for T-Mobile gateway
sudo nmcli con add type bridge con-name br-ispb ifname br-ispb
sudo nmcli con add type ethernet con-name br-ispb-port ifname eno1 master br-ispb
sudo nmcli con up br-ispb
# Create br-ha (internal only, no physical port)
sudo nmcli con add type bridge con-name br-ha ifname br-ha
sudo nmcli con up br-ha
| VyOS eth | Bridge | Purpose |
|---|---|---|
eth0 |
br-wan |
ISP-A WAN (existing) |
eth1 |
br-ispb |
ISP-B WAN (T-Mobile) |
eth2 |
br-mgmt |
LAN trunk |
eth3 |
br-ha |
HA sync |
PE Reality and Handoff Behavior
What the Upstream PE Actually Is
Neither iFog nor ROUTE64 ships hardware. There is no CPE, no Cradlepoint, no physical handoff of any kind. The PE is a software router in a datacenter connected exclusively via WireGuard tunnel over your home ISP circuits.
| Upstream | PE platform | Notes |
|---|---|---|
iFog AS34927 |
Linux x86, FRR or BIRD BGP daemon |
Fremont PoP closest to Pasadena. 100Mbps tunnel cap. 1TB/mo fair use. No SLA. Non-commercial only. |
ROUTE64 |
VyOS-based, BIRD BGP daemon, VPP data plane |
Automated IRR/RPKI filter refresh every 3h. Self-service portal. No SLA. |
[VyOS node]
| WireGuard UDP (encrypted, over home ISP circuit)
[iFog or ROUTE64 Linux PE — datacenter x86]
| Their upstream transit (Cogent, Telia, HE, etc.)
[Internet DFZ]
PE Handoff Scenarios
| Event | What happens | Recovery mechanism |
|---|---|---|
iFog PE internal reroute |
WireGuard endpoint unreachable briefly. BGP sessions to iFog drop on both nodes. |
BFD detects in <1s (wired) or <2s (cellular). BGP withdraws iFog paths. ROUTE64 sole upstream. Reconverges in 2–5s. |
ROUTE64 PE failure |
Mirror of above. |
iFog becomes sole upstream. |
ISP-A (wired) goes down |
vyos1 VRF WAN-A loses default route. iFog wg0 keepalives stop. BFD triggers. |
VRF WAN-B becomes active on vyos1. Tunnels re-establish via ISP-B. vyos2 unaffected. |
ISP-B (T-Mobile) goes down |
Mirror of above on vyos2. |
VRF WAN-A fallback on vyos2. |
vyos1 node failure |
VRRP: vyos2 assumes all VRID mastership (~2–3s). BGP: DFZ reconverges to vyos2 paths only. |
conntrack-sync external-cache on vyos2 preserves established sessions. |
vyos2 node failure |
Mirror of above. |
conntrack-sync on vyos1 handles it. |
Phase 1: Procurement
Procurement Checklist
Complete these in order. Each step unlocks the next.
| Step | Action | Link / Source | Est. Cost |
|---|---|---|---|
1 |
Verify T-Mobile 5G Home Internet coverage at your address. If available, order online — ships via mail, self-install. |
~$50/mo |
|
2 |
Contact Voldeta for RIPE sponsorship — request ASN + PI /48. Email or use their portal. Provide: org name, two upstream ASNs (AS34927 iFog, ROUTE64 ASN from bgp.tools), use case. |
~€120 first year |
|
3 |
Create iFog BGPTunnel account — verify ASN once issued. Create TWO WireGuard tunnels (one per VyOS node). Select Fremont PoP. Record: endpoint, peer pubkey, link /127 addresses. |
Free |
|
4 |
Create ROUTE64 account — verify ASN. Create TWO WireGuard tunnels (one per VyOS node). Record: endpoint, peer pubkey, link /127 addresses. |
Free |
|
5 |
Create RIPE database objects — route6, aut-num (see 1.4). Create RPKI ROA via my.ripe.net. |
Included |
|
6 |
Create br-ispb and br-ha bridges on both hypervisors. Connect T-Mobile gateway to eno1 port. |
See KVM Bridge Layout above |
— |
7 |
Complete Phase 1.5 — Add vNICs to VyOS VMs using VRRP zero-downtime migration procedure. |
See Phase 1.5 below |
— |
|
Recommended Order
Start with Step 2 (Voldeta/RIPE) first — ASN approval takes 3–7 business days. Order T-Mobile (Step 1) in parallel. By the time T-Mobile is set up, your ASN should be ready for Steps 3–5. No additional NICs needed — your Supermicro E300-9D has 6 unused 10GbE ports (eno1–eno6). |
1.1 Hardware
Your Supermicro E300-9D-8CN8TP has 8x RJ45 10GbE ports. Current usage:
-
eno7 → br-wan (ISP-A modem) — existing
-
eno8 → br-mgmt (LAN trunk) — existing
-
eno1–eno6 → available
No additional NIC purchase required. Use eno1 for T-Mobile gateway.
-
Order T-Mobile 5G Home Internet — t-mobile.com/home-internet
1.2 RIPE Sponsoring LIR — ASN + PI /48
Recommended: voldeta.com
RIPE NCC base fees: €50/yr ASN + €50/yr PI /48. Voldeta passes these through at cost. Expected all-in: ~€120/year.
Organization name : Domus Digitalis Network
(individual registration accepted)
Upstream ASN 1 : AS34927 (iFog BGPTunnel)
Upstream ASN 2 : <ROUTE64 ASN — verify on bgp.tools>
Use description : Home enterprise network, BGP multihoming,
non-commercial research and learning
Country : United States
(RIPE sponsoring is not region-restricted)
Expected RIPE processing: 3–7 business days.
1.3 Sign Up at Both Upstreams
| Provider | Portal | Steps |
|---|---|---|
iFog BGPTunnel |
bgptunnel.com |
Create account. Verify ASN. Create two WireGuard tunnels — one for vyos1, one for vyos2. Select Fremont PoP. Record: endpoint IP:port, peer pubkey, /127 link addr (both ends). |
ROUTE64 |
route64.org |
Create account. Create two WireGuard tunnels — one per node. Record: endpoint IP:port, peer pubkey, /127 link addr (both ends). |
You will have four tunnel parameter sets when done:
ifog-vyos1 : endpoint, peer-pubkey, my-link-addr/127, peer-addr
ifog-vyos2 : endpoint, peer-pubkey, my-link-addr/127, peer-addr
r64-vyos1 : endpoint, peer-pubkey, my-link-addr/127, peer-addr
r64-vyos2 : endpoint, peer-pubkey, my-link-addr/127, peer-addr
1.4 RIPE Database Objects
Create after resources are issued. Both upstreams enforce IRR-based prefix filters — missing objects means your prefix is silently dropped at their PE and never propagates into the DFZ.
route6 Object
route6: {domus-prefix}
descr: Domus Digitalis PI block
origin: {domus-asn}
mnt-by: DOMUS-MNT
source: RIPE
aut-num Object
aut-num: {domus-asn}
as-name: DOMUS-DIGITALIS
descr: Domus Digitalis Home Enterprise Network
mp-import: from {ifog-asn} accept ANY
mp-import: from {route64-asn} accept ANY
mp-export: to {ifog-asn} announce {domus-asn}
mp-export: to {route64-asn} announce {domus-asn}
admin-c: <YOUR-RIPE-HANDLE>
tech-c: <YOUR-RIPE-HANDLE>
mnt-by: DOMUS-MNT
source: RIPE
Phase 1.5: VRRP Zero-Downtime Interface Migration
This procedure adds 2 vNICs (br-ispb, br-ha) to each VyOS VM and fixes the interface order on vyos-02 — all without downtime. VRRP ensures one node is always forwarding traffic.
Current State
| VM | eth0 | eth1 |
|---|---|---|
vyos-01 |
br-wan (WAN) |
br-mgmt (LAN) |
vyos-02 |
br-mgmt (LAN) — WRONG |
br-wan (WAN) — WRONG |
Both VMs have only 2 interfaces. vyos-02 has them swapped.
Target State
| VM | eth0 | eth1 | eth2 | eth3 |
|---|---|---|---|---|
vyos-01 |
br-wan (ISP-A) |
br-ispb (ISP-B) |
br-mgmt (LAN) |
br-ha (sync) |
vyos-02 |
br-wan (ISP-A) |
br-ispb (ISP-B) |
br-mgmt (LAN) |
br-ha (sync) |
Prerequisites
Take VM Snapshots (BEFORE ANY CHANGES)
Test snapshot/revert workflow first — validate safety net before trusting it.
# On kvm-02 — test with BACKUP node (no traffic impact)
sudo virsh snapshot-create-as vyos-02 test-snapshot "Testing snapshot workflow"
# Verify snapshot exists
sudo virsh snapshot-list vyos-02
# Make a harmless change on vyos-02
ssh vyos-02 "configure; set system host-name vyos-02-TEST; commit; save"
# Verify change applied
ssh vyos-02 "show host name"
# Expected: vyos-02-TEST
# Revert snapshot
sudo virsh snapshot-revert vyos-02 test-snapshot
# Wait for VM to come back
sleep 10
# Verify change is gone
ssh vyos-02 "show host name"
# Expected: vyos-02 (original)
# Clean up test snapshot
sudo virsh snapshot-delete vyos-02 test-snapshot
# Snapshot workflow validated ✓
Now create the real snapshots:
# On kvm-01
sudo virsh snapshot-create-as vyos-01 pre-bgp-migration "Before 4-NIC migration"
# On kvm-02
sudo virsh snapshot-create-as vyos-02 pre-bgp-migration "Before 4-NIC migration"
# Verify snapshots created
sudo virsh snapshot-list vyos-01
sudo virsh snapshot-list vyos-02
sudo virsh snapshot-revert vyos-01 pre-bgp-migration
sudo virsh snapshot-revert vyos-02 pre-bgp-migration
|
Delete Snapshots After Success
Snapshots degrade disk I/O performance. Delete within 24–48 hours after confirming migration success:
|
Export Current Firewall Config
# On vyos-01 — export full config
ssh vyos-01 "show configuration commands" > ~/vyos-01-config-$(date +%F).txt
# On vyos-02 — export full config
ssh vyos-02 "show configuration commands" > ~/vyos-02-config-$(date +%F).txt
# Extract firewall rules specifically
ssh vyos-01 "show configuration commands | grep firewall" > ~/vyos-01-firewall-$(date +%F).txt
ssh vyos-02 "show configuration commands | grep firewall" > ~/vyos-02-firewall-$(date +%F).txt
# Find all rules referencing eth1 (will need to change to eth2)
ssh vyos-01 "show configuration commands | grep eth1"
ssh vyos-02 "show configuration commands | grep eth1"
# Copy to NAS for safekeeping
scp ~/vyos-*-$(date +%F).txt nas-01:/volume1/backups/vyos/
Create KVM Bridges
# On both hypervisors — create br-ispb and br-ha bridges
sudo nmcli con add type bridge con-name br-ispb ifname br-ispb
sudo nmcli con add type ethernet con-name br-ispb-port ifname eno1 master br-ispb
sudo nmcli con up br-ispb
sudo nmcli con add type bridge con-name br-ha ifname br-ha
sudo nmcli con up br-ha
# Verify
bridge link show
Step 1: Fix vyos-02 (Currently VRRP BACKUP)
vyos-02 is BACKUP — no traffic impact when powered off.
# On kvm-02 — verify vyos-02 is BACKUP
ssh vyos-02 "show vrrp" | awk '/State/ {print $3}'
# Expected: BACKUP (all VRIDs)
# Shutdown vyos-02
sudo virsh shutdown vyos-02
# Wait for clean shutdown
watch -n1 'sudo virsh list --all | grep vyos-02'
# Remove old interfaces (wrong order)
sudo virsh detach-interface vyos-02 bridge --mac $(sudo virsh domiflist vyos-02 | awk 'NR==3 {print $5}') --persistent
sudo virsh detach-interface vyos-02 bridge --mac $(sudo virsh domiflist vyos-02 | awk 'NR==3 {print $5}') --persistent
# Attach new interfaces in correct order
sudo virsh attach-interface vyos-02 bridge br-wan --model virtio --persistent
sudo virsh attach-interface vyos-02 bridge br-ispb --model virtio --persistent
sudo virsh attach-interface vyos-02 bridge br-mgmt --model virtio --persistent
sudo virsh attach-interface vyos-02 bridge br-ha --model virtio --persistent
# Verify interface order
sudo virsh domiflist vyos-02
# Expected:
# eth0 → br-wan
# eth1 → br-ispb
# eth2 → br-mgmt
# eth3 → br-ha
# Start vyos-02
sudo virsh start vyos-02
# Verify VyOS sees interfaces
ssh vyos-02 "show interfaces"
Step 2: Reconfigure vyos-02 VyOS
# SSH to vyos-02 — reconfigure interface addresses
configure
# eth0 is now WAN (was LAN)
delete interfaces ethernet eth0 address
set interfaces ethernet eth0 description 'WAN-A-ISPA'
set interfaces ethernet eth0 address 'dhcp'
# eth1 is ISP-B (new)
set interfaces ethernet eth1 description 'WAN-B-ISPB'
set interfaces ethernet eth1 address 'dhcp'
# eth2 is LAN (was eth0)
delete interfaces ethernet eth1 address 10.50.1.3/24
set interfaces ethernet eth2 description 'INTERNAL-TRUNK'
set interfaces ethernet eth2 address '10.50.1.3/24'
# eth3 is HA sync (new)
set interfaces ethernet eth3 description 'HA-SYNC'
set interfaces ethernet eth3 address '10.50.99.2/30'
# Update VRRP interface references
set high-availability vrrp group MGMT interface 'eth2'
set high-availability vrrp group MGMT hello-source-address '10.50.1.3'
commit
save
# Verify VRRP is BACKUP
show vrrp
# All groups should show BACKUP
Step 3: Failover to vyos-02
# On vyos-01 — reduce VRRP priority to trigger failover
configure
set high-availability vrrp group MGMT priority 50
commit
# Verify vyos-02 becomes MASTER
ssh vyos-02 "show vrrp"
# Expected: MASTER
Step 4: Fix vyos-01 (Now VRRP BACKUP)
# On kvm-01
sudo virsh shutdown vyos-01
# Detach old interfaces
sudo virsh detach-interface vyos-01 bridge --mac $(sudo virsh domiflist vyos-01 | awk 'NR==3 {print $5}') --persistent
sudo virsh detach-interface vyos-01 bridge --mac $(sudo virsh domiflist vyos-01 | awk 'NR==3 {print $5}') --persistent
# Attach new interfaces in correct order
sudo virsh attach-interface vyos-01 bridge br-wan --model virtio --persistent
sudo virsh attach-interface vyos-01 bridge br-ispb --model virtio --persistent
sudo virsh attach-interface vyos-01 bridge br-mgmt --model virtio --persistent
sudo virsh attach-interface vyos-01 bridge br-ha --model virtio --persistent
# Start
sudo virsh start vyos-01
Step 5: Reconfigure vyos-01 VyOS
# SSH to vyos-01
configure
# eth2 is now LAN (was eth1)
delete interfaces ethernet eth1 address 10.50.1.2/24
set interfaces ethernet eth2 description 'INTERNAL-TRUNK'
set interfaces ethernet eth2 address '10.50.1.2/24'
# eth1 is ISP-B (new)
set interfaces ethernet eth1 description 'WAN-B-ISPB'
set interfaces ethernet eth1 address 'dhcp'
# eth3 is HA sync (new)
set interfaces ethernet eth3 description 'HA-SYNC'
set interfaces ethernet eth3 address '10.50.99.1/30'
# Update VRRP interface references
set high-availability vrrp group MGMT interface 'eth2'
set high-availability vrrp group MGMT hello-source-address '10.50.1.2'
# Restore priority
set high-availability vrrp group MGMT priority 200
commit
save
Step 6: Verify Final State
# On both nodes
show interfaces
show vrrp
ping 10.50.99.2 # From vyos-01 — HA link test
ping 10.50.99.1 # From vyos-02 — HA link test
| Check | vyos-01 | vyos-02 |
|---|---|---|
VRRP role |
MASTER (priority 200) |
BACKUP (priority 100) |
eth0 |
br-wan (dhcp) |
br-wan (dhcp) |
eth1 |
br-ispb (dhcp) |
br-ispb (dhcp) |
eth2 |
10.50.1.2/24 |
10.50.1.3/24 |
eth3 |
10.50.99.1/30 |
10.50.99.2/30 |
HA ping |
✓ |
✓ |
Step 7: Migrate Firewall Rules
The LAN interface moved from eth1 → eth2. Update all firewall rules.
7.1 Identify Rules to Update
# Compare exported config to find eth1 references
cat ~/vyos-01-firewall-$(date +%F).txt | grep eth1
7.2 Update Zone Definitions
# On vyos-01
configure
# Update LAN zone to use eth2
delete firewall zone LAN interface eth1
set firewall zone LAN interface eth2
# Add ISP-B zone for eth1 (new WAN)
set firewall zone WAN-B interface eth1
# Add HA zone for eth3
set firewall zone HA interface eth3
7.3 Update NAT Rules
# NAT source rules — add eth1 (ISP-B) outbound masquerade
set nat source rule 20 description 'IPv4 outbound via ISP-B'
set nat source rule 20 outbound-interface name 'eth1'
set nat source rule 20 source address '10.50.0.0/16'
set nat source rule 20 translation address 'masquerade'
7.4 Add HA Sync Rules
# Allow conntrack-sync on eth3
set firewall ipv4 name HA-LOCAL default-action drop
set firewall ipv4 name HA-LOCAL rule 10 action accept
set firewall ipv4 name HA-LOCAL rule 10 description 'conntrack-sync'
set firewall ipv4 name HA-LOCAL rule 10 protocol udp
set firewall ipv4 name HA-LOCAL rule 10 destination port 3780
set firewall ipv4 name HA-LOCAL rule 20 action accept
set firewall ipv4 name HA-LOCAL rule 20 description 'VRRP multicast'
set firewall ipv4 name HA-LOCAL rule 20 protocol vrrp
set firewall ipv4 name HA-LOCAL rule 30 action accept
set firewall ipv4 name HA-LOCAL rule 30 description 'ICMP ping'
set firewall ipv4 name HA-LOCAL rule 30 protocol icmp
# Apply to eth3
set firewall interface eth3 local name HA-LOCAL
7.5 Add ISP-B WAN Rules
# eth1 (ISP-B) gets same treatment as eth0 (ISP-A)
# Copy existing WAN rules to WAN-B
set firewall ipv4 name WAN-B-LOCAL default-action drop
set firewall ipv4 name WAN-B-LOCAL rule 10 action accept
set firewall ipv4 name WAN-B-LOCAL rule 10 description 'established/related'
set firewall ipv4 name WAN-B-LOCAL rule 10 state established
set firewall ipv4 name WAN-B-LOCAL rule 10 state related
set firewall ipv4 name WAN-B-LOCAL rule 20 action accept
set firewall ipv4 name WAN-B-LOCAL rule 20 description 'WireGuard UDP'
set firewall ipv4 name WAN-B-LOCAL rule 20 protocol udp
set firewall ipv4 name WAN-B-LOCAL rule 20 destination port 51820
# Apply to eth1
set firewall interface eth1 local name WAN-B-LOCAL
7.6 Commit and Verify
commit
save
# Verify firewall zones
show firewall zone
# Verify interface assignments
show firewall interface
# Test connectivity from LAN
# (from a client, ping gateway, access internet)
7.7 Replicate to vyos-02
# SSH to vyos-02 and apply same firewall changes
ssh vyos-02
configure
# ... repeat 7.2-7.6 ...
| Interface | Old Role | New Role / Rules |
|---|---|---|
eth0 |
WAN (ISP-A) |
No change |
eth1 |
LAN |
ISP-B WAN — add WAN-B-LOCAL ruleset |
eth2 |
— |
LAN — move LAN zone here |
eth3 |
— |
HA sync — add HA-LOCAL ruleset |
Phase 2: VyOS Configuration
2.1 Interface Addressing
| Interface | vyos1 | vyos2 | Purpose |
|---|---|---|---|
eth0 (ISP-A) |
dhcp (VRF WAN-A) |
dhcp (VRF WAN-A fallback) |
WAN-A uplink |
eth1 (ISP-B) |
dhcp (VRF WAN-B fallback) |
dhcp (VRF WAN-B) |
WAN-B uplink |
eth2 (internal) |
10.50.10.11/24 |
10.50.10.12/24 |
Downstream trunk. VRRP VIPs. |
eth3 (HA) |
10.50.99.1/30 |
10.50.99.2/30 |
conntrack-sync + VRRP peer comms. |
# vyos1 base interfaces
set interfaces ethernet eth0 description 'WAN-A-ISPA'
set interfaces ethernet eth0 vrf 'WAN-A'
set interfaces ethernet eth0 address 'dhcp'
set interfaces ethernet eth1 description 'WAN-B-ISPB'
set interfaces ethernet eth1 vrf 'WAN-B'
set interfaces ethernet eth1 address 'dhcp'
set interfaces ethernet eth2 description 'INTERNAL-TRUNK'
set interfaces ethernet eth2 address '10.50.10.11/24'
set interfaces ethernet eth3 description 'HA-SYNC'
set interfaces ethernet eth3 address '10.50.99.1/30'
2.2 VRF Configuration
VRF provides clean L3 separation between WAN paths. Unlike policy routing tables, VRF survives DHCP lease changes and is the enterprise standard for multi-homing on a single router.
# Define VRFs
set vrf name WAN-A table '100'
set vrf name WAN-B table '200'
# Assign WAN interfaces to VRFs
set interfaces ethernet eth0 vrf 'WAN-A'
set interfaces ethernet eth1 vrf 'WAN-B'
# Default routes within each VRF (populated by DHCP automatically
# when interface is in the VRF — verify with 'show vrf WAN-A route')
# Static fallback: vyos1 falls back to WAN-B if WAN-A fails
# (lower metric = preferred, higher = fallback)
set protocols static vrf WAN-A route '::/0' interface 'eth0' metric '10'
set protocols static vrf WAN-B route '::/0' interface 'eth1' metric '20'
# vyos2: WAN-B is primary (metric 10), WAN-A is fallback (metric 20)
|
VRF vs Policy Routing
Policy routing (set policy route … set table N) works but is fragile under DHCP — if your WAN IP changes, the source-address match in the policy rule may no longer match, breaking tunnel source binding silently. VRF binds the entire interface to a routing table, so DHCP lease renewal always lands in the correct table regardless of IP. |
2.3 WireGuard Tunnels
Each node builds two WireGuard tunnels — one to iFog, one to ROUTE64. Tunnels are bound to their VRF via the source-address attribute, ensuring each tunnel sources from the correct WAN interface.
# Generate keypairs first (run on each node):
# run generate pki wireguard key-pair
# Submit the public-key to iFog and ROUTE64 portals
# vyos1 — iFog tunnel (wg0), sourced via VRF WAN-A
set interfaces wireguard wg0 description 'iFog-Fremont-vyos1'
set interfaces wireguard wg0 address '<ifog-v1-link-addr>/127'
set interfaces wireguard wg0 private-key '<vyos1-wg0-privkey>'
set interfaces wireguard wg0 vrf 'WAN-A'
set interfaces wireguard wg0 peer IFOG public-key '<ifog-pubkey>'
set interfaces wireguard wg0 peer IFOG endpoint '<ifog-v1-endpoint>'
set interfaces wireguard wg0 peer IFOG allowed-ips '::/0'
set interfaces wireguard wg0 peer IFOG persistent-keepalive '25'
# vyos1 — ROUTE64 tunnel (wg1), sourced via VRF WAN-B
set interfaces wireguard wg1 description 'ROUTE64-vyos1'
set interfaces wireguard wg1 address '<r64-v1-link-addr>/127'
set interfaces wireguard wg1 private-key '<vyos1-wg1-privkey>'
set interfaces wireguard wg1 vrf 'WAN-B'
set interfaces wireguard wg1 peer R64 public-key '<r64-pubkey>'
set interfaces wireguard wg1 peer R64 endpoint '<r64-v1-endpoint>'
set interfaces wireguard wg1 peer R64 allowed-ips '::/0'
set interfaces wireguard wg1 peer R64 persistent-keepalive '25'
# vyos2: mirror with vyos2 keypairs/link-addrs
# wg0 (iFog) → VRF WAN-B (vyos2 primary WAN is ISP-B)
# wg1 (ROUTE64) → VRF WAN-A
|
T-Mobile CGNAT and WireGuard
T-Mobile 5G Home Internet uses CGNAT — your gateway has a private IP and shares a public IP with other subscribers. Outbound WireGuard works correctly because UDP NAT state is maintained by persistent keepalives (set to 25s, under the typical 30s NAT timeout). T-Mobile occasionally reassigns the CGNAT external IP — the gateway reboot causes a brief WireGuard re-handshake delay (~15–30s) before the tunnel recovers. BFD and BGP timers are tuned to tolerate this. |
2.4 BGP Configuration
Both nodes share ASyyyyyy. Each independently peers with both upstreams. BGP runs in the global routing table but sources sessions via the WireGuard tunnel link addresses.
# vyos1
set protocols bgp system-as '{domus-asn}'
set protocols bgp parameters router-id '10.50.1.11'
set protocols bgp parameters bestpath as-path multipath-relax
# iFog peer (wg0 link address)
set protocols bgp neighbor '<ifog-v1-peer-addr>' remote-as '{ifog-asn}'
set protocols bgp neighbor '<ifog-v1-peer-addr>' description 'iFog-BGPTunnel'
set protocols bgp neighbor '<ifog-v1-peer-addr>' timers holdtime '30'
set protocols bgp neighbor '<ifog-v1-peer-addr>' timers keepalive '10'
set protocols bgp neighbor '<ifog-v1-peer-addr>' bfd
set protocols bgp neighbor '<ifog-v1-peer-addr>' address-family ipv6-unicast
set protocols bgp neighbor '<ifog-v1-peer-addr>' address-family ipv6-unicast \
route-map export 'RM-OUT-IFOG'
set protocols bgp neighbor '<ifog-v1-peer-addr>' address-family ipv6-unicast \
route-map import 'RM-IN-IFOG'
# ROUTE64 peer (wg1 link address)
set protocols bgp neighbor '<r64-v1-peer-addr>' remote-as '{route64-asn}'
set protocols bgp neighbor '<r64-v1-peer-addr>' description 'ROUTE64'
set protocols bgp neighbor '<r64-v1-peer-addr>' timers holdtime '30'
set protocols bgp neighbor '<r64-v1-peer-addr>' timers keepalive '10'
set protocols bgp neighbor '<r64-v1-peer-addr>' bfd
set protocols bgp neighbor '<r64-v1-peer-addr>' address-family ipv6-unicast
set protocols bgp neighbor '<r64-v1-peer-addr>' address-family ipv6-unicast \
route-map export 'RM-OUT-R64'
set protocols bgp neighbor '<r64-v1-peer-addr>' address-family ipv6-unicast \
route-map import 'RM-IN-R64'
# Advertise PI prefix
set protocols bgp address-family ipv6-unicast network '{domus-prefix}'
# RPKI validation
set protocols rpki cache RIPE address 'rpki.ripe.net'
set protocols rpki cache RIPE port '3323'
set protocols rpki cache RIPE preference '1'
# vyos2: router-id 10.50.1.12
# Route-map local-pref values are flipped (see 2.5)
2.5 BGP Route Maps — Active-Active Traffic Split
vyos1 is the preferred inbound path via iFog. vyos2 is preferred via ROUTE64. AS-path prepending signals this preference into the DFZ.
# Prefix list — PI block exact match only
set policy prefix-list6 PL-MY-PREFIX rule 10 action 'permit'
set policy prefix-list6 PL-MY-PREFIX rule 10 prefix '{domus-prefix}'
set policy prefix-list6 PL-MY-PREFIX rule 10 le '48'
# --- vyos1 route-maps ---
# Outbound to iFog — clean advertisement (vyos1 preferred inbound via iFog)
set policy route-map RM-OUT-IFOG rule 10 action 'permit'
set policy route-map RM-OUT-IFOG rule 10 match ipv6 address \
prefix-list 'PL-MY-PREFIX'
set policy route-map RM-OUT-IFOG rule 20 action 'deny'
# Outbound to ROUTE64 — prepend twice (signals DFZ to prefer vyos2 via ROUTE64)
set policy route-map RM-OUT-R64 rule 10 action 'permit'
set policy route-map RM-OUT-R64 rule 10 match ipv6 address \
prefix-list 'PL-MY-PREFIX'
set policy route-map RM-OUT-R64 rule 10 set as-path-prepend \
'{domus-asn} {domus-asn}'
set policy route-map RM-OUT-R64 rule 20 action 'deny'
# Inbound from iFog — preferred (local-pref 150)
set policy route-map RM-IN-IFOG rule 10 action 'permit'
set policy route-map RM-IN-IFOG rule 10 set local-preference '150'
# Inbound from ROUTE64 — fallback (local-pref 100)
set policy route-map RM-IN-R64 rule 10 action 'permit'
set policy route-map RM-IN-R64 rule 10 set local-preference '100'
# --- vyos2 differences ---
# RM-OUT-IFOG: add prepend (vyos2 not preferred inbound via iFog)
# RM-OUT-R64: no prepend (vyos2 preferred inbound via ROUTE64)
# RM-IN-IFOG: local-pref 100
# RM-IN-R64: local-pref 150
2.6 BFD — Per-ISP Tuned Timers
BFD timers are tuned differently per WAN path. The wired ISP-A path is stable — tight timers give fast detection. T-Mobile cellular exhibits jitter — looser timers avoid false positives causing unnecessary reconvergence.
# vyos1 — iFog peer (tunnel over ISP-A wired — tight timers)
set protocols bfd peer '<ifog-v1-peer-addr>' interval multiplier '3'
set protocols bfd peer '<ifog-v1-peer-addr>' interval receive '300'
set protocols bfd peer '<ifog-v1-peer-addr>' interval transmit '300'
# Detection window: 300ms x 3 = 900ms
# vyos1 — ROUTE64 peer (tunnel over ISP-B cellular — relaxed timers)
set protocols bfd peer '<r64-v1-peer-addr>' interval multiplier '4'
set protocols bfd peer '<r64-v1-peer-addr>' interval receive '500'
set protocols bfd peer '<r64-v1-peer-addr>' interval transmit '500'
# Detection window: 500ms x 4 = 2000ms — tolerates cellular jitter
# Link BFD to BGP neighbors
set protocols bgp neighbor '<ifog-v1-peer-addr>' bfd
set protocols bgp neighbor '<r64-v1-peer-addr>' bfd
# vyos2: mirror, but swap timer profiles
# iFog tunnel on vyos2 → ISP-B (cellular) → use 500/4
# ROUTE64 tunnel on vyos2 → ISP-A (wired) → use 300/3
2.7 BGP Graceful Shutdown
Use graceful shutdown for maintenance to signal peers cleanly before dropping sessions. This prevents black-holing traffic during planned work.
# Before any maintenance — send NOTIFICATION with Administrative Shutdown
# Peers drain traffic gracefully before session drops
set protocols bgp neighbor '<ifog-v1-peer-addr>' shutdown
# After maintenance is complete — restore
delete protocols bgp neighbor '<ifog-v1-peer-addr>' shutdown
2.8 VRRP — Split Master Downstream
# vyos1: MASTER DATA (VRID 10), BACKUP VOICE (VRID 20)
set high-availability vrrp group DATA-GW interface 'eth2'
set high-availability vrrp group DATA-GW vrid '10'
set high-availability vrrp group DATA-GW address '10.50.10.1/24'
set high-availability vrrp group DATA-GW priority '150'
set high-availability vrrp group DATA-GW hello-source-address '10.50.10.11'
set high-availability vrrp group DATA-GW peer-address '10.50.10.12'
set high-availability vrrp group DATA-GW no-preempt
set high-availability vrrp group VOICE-GW interface 'eth2'
set high-availability vrrp group VOICE-GW vrid '20'
set high-availability vrrp group VOICE-GW address '10.50.20.1/24'
set high-availability vrrp group VOICE-GW priority '100'
set high-availability vrrp group VOICE-GW hello-source-address '10.50.10.11'
set high-availability vrrp group VOICE-GW peer-address '10.50.10.12'
set high-availability vrrp group VOICE-GW no-preempt
set high-availability vrrp sync-group SYNC member 'DATA-GW'
set high-availability vrrp sync-group SYNC member 'VOICE-GW'
# vyos2: DATA-GW priority 100, VOICE-GW priority 150
2.9 conntrack-sync
# Both nodes — peer address differs only
set service conntrack-sync accept-protocol 'tcp'
set service conntrack-sync accept-protocol 'udp'
set service conntrack-sync accept-protocol 'icmp'
set service conntrack-sync failover-mechanism vrrp sync-group 'SYNC'
set service conntrack-sync interface 'eth3' peer '10.50.99.2'
set service conntrack-sync event-listen-queue-size '8'
set service conntrack-sync sync-queue-size '8'
# vyos2: peer '10.50.99.1'
2.10 Dual-Stack — NAT44 for IPv4 Clients
BGP carries your PI /48 IPv6 space only. IPv4 outbound for legacy devices uses SNAT masquerade via the active WAN interface. Clients receive both RFC1918 IPv4 (DHCP) and a routable IPv6 from your /48 (SLAAC or DHCPv6).
# NAT44 — masquerade IPv4 outbound via ISP-A WAN
set nat source rule 10 description 'IPv4 outbound via ISP-A'
set nat source rule 10 outbound-interface name 'eth0'
set nat source rule 10 source address '10.50.0.0/16'
set nat source rule 10 translation address 'masquerade'
# NAT44 — masquerade IPv4 outbound via ISP-B WAN
set nat source rule 20 description 'IPv4 outbound via ISP-B'
set nat source rule 20 outbound-interface name 'eth1'
set nat source rule 20 source address '10.50.0.0/16'
set nat source rule 20 translation address 'masquerade'
# IPv6 downstream — advertise PI /48 subnets via Router Advertisements
# Allocate a /64 per VLAN from your /48
# Example: DATA VLAN gets 2a0e:xxxx:0:10::/64
set service router-advert interface 'eth2' prefix '{domus-prefix}'
|
IPv6 Subnet Allocation from PI /48
Your /48 provides 65,536 /64 subnets. Allocate one /64 per VLAN: DATA VLAN 10 → 2a0e:xxxx:0:10::/64 VOICE VLAN 20 → 2a0e:xxxx:0:20::/64 GUEST VLAN 30 → 2a0e:xxxx:0:30::/64 IoT VLAN 40 → 2a0e:xxxx:0:40::/64 MGMT VLAN 50 → 2a0e:xxxx:0:50::/64 Clients use SLAAC (stateless address autoconfiguration) to self-assign addresses from the /64. No DHCPv6 required unless you want managed addressing. |
Phase 3: Verification
WireGuard Tunnel Health
show interfaces wireguard wg0
show interfaces wireguard wg1
# latest-handshake should be < 30 seconds
ping6 <ifog-v1-peer-addr> interface wg0 count 5
ping6 <r64-v1-peer-addr> interface wg1 count 5
VRF Routing Tables
show vrf WAN-A route
show vrf WAN-B route
# Each should have a default route via its WAN interface
ip -6 route show vrf WAN-A
ip -6 route show vrf WAN-B
BGP Session State
show bgp summary
# Expect: 2 neighbors, both Established, non-zero prefixes received
show bgp ipv6 unicast {domus-prefix}
# Expect: 2 paths — one via iFog, one via ROUTE64
show bgp ipv6 unicast neighbors <ifog-peer> advertised-routes
# Expect: {domus-prefix} advertised outbound
RPKI Validation
show rpki prefix-table
# Your prefix should appear as valid
# External check
curl -s "https://rpki.cloudflare.com/api/v1/validity/\
{domus-asn}/{domus-prefix}" | python3 -m json.tool
VRRP, conntrack-sync, BFD
show vrrp
# vyos1: DATA-GW MASTER, VOICE-GW BACKUP
# vyos2: DATA-GW BACKUP, VOICE-GW MASTER
show conntrack-sync statistics
# internal-cache non-zero on active node
# external-cache on standby matches internal-cache count
show bfd peers
# Both peers: state Up
External Prefix Visibility
# Check DFZ propagation
# Visit bgp.tools → search your ASN
# Prefix should be visible from multiple vantage points
# Verify AS-path prepend is working
# Visit lg.he.net → traceroute/BGP lookup for your prefix
# Via iFog: AS34927 {domus-asn}
# Via ROUTE64 from vyos1: AS{r64} {domus-asn} {domus-asn}
# Via ROUTE64 from vyos2: AS{r64} {domus-asn}
Phase 4: Failover Testing
Test 1 — PE Handoff (iFog tunnel drop)
# Establish long-lived TCP session through the network first (e.g. iperf6)
# Bring down iFog WireGuard tunnel on vyos1:
sudo ip link set wg0 down
# Expected sequence:
# t+0.9s BFD declares iFog peer down (wired timer: 300ms x 3)
# t+1s BGP withdraws iFog paths on vyos1
# t+3-5s DFZ reconverges — all inbound via ROUTE64
# TCP session survives — conntrack-sync preserved state on vyos2
sudo ip link set wg0 up
# BGP re-establishes, iFog paths return
Test 2 — ISP-A Physical Circuit Failure
# Disable eth0 on vyos1 (simulates cable cut)
set interfaces ethernet eth0 disable
commit
# Expected:
# VRF WAN-A loses default route on vyos1
# iFog wg0 tunnel keepalives stop → BFD triggers
# VRF WAN-B becomes active path for vyos1 tunnels
# vyos2 unaffected — already on ISP-B primary
delete interfaces ethernet eth0 disable
commit
Test 3 — Node Failure
# Power off or pause vyos1 KVM VM
virsh suspend vyos1
# Verify on vyos2:
show vrrp # Both VRIDs should be MASTER on vyos2
show bgp summary # Both sessions still Established (vyos2 independent)
show conntrack-sync statistics # Sessions flowing from external-cache
virsh resume vyos1
# vyos1 re-establishes BGP, VRRP transitions back to split-master
Test 4 — T-Mobile Gateway Reboot
# Reboot T-Mobile gateway (power cycle)
# WireGuard tunnel over ISP-B will drop for ~30-60s during reboot
# Expected on vyos2:
# BFD on ROUTE64 peer (ISP-B path): 500ms x 4 = 2s detection
# BGP withdraws ROUTE64 paths on vyos2
# iFog (via ISP-A fallback VRF) becomes sole path
# After T-Mobile recovers: WireGuard re-handshakes,
# BGP re-establishes, ROUTE64 paths return
Reference
Quick Command Reference
# BGP
show bgp summary
show bgp ipv6 unicast
show bgp ipv6 unicast neighbors <addr> advertised-routes
show bgp ipv6 unicast neighbors <addr> received-routes
# Graceful shutdown (before maintenance)
set protocols bgp neighbor <peer> shutdown
delete protocols bgp neighbor <peer> shutdown
# VRRP
show vrrp
show vrrp detail
# conntrack-sync
show conntrack-sync statistics
show conntrack-sync status
# BFD
show bfd peers
show bfd peers detail
# VRF
show vrf
show vrf WAN-A route
show vrf WAN-B route
# WireGuard
show interfaces wireguard wg0
show interfaces wireguard wg1
# IPv6 routing
show ipv6 route
show ipv6 route bgp
# nftables
sudo nft list ruleset | grep -A5 ip6
# RPKI
show rpki prefix-table
show rpki cache-connection
External Tools
| Tool | Purpose |
|---|---|
bgp.tools |
View ASN, prefix propagation, AS paths globally. Search your ASN after prefix goes live. |
lg.he.net |
Hurricane Electric looking glass. Verify AS-path prepend from multiple vantage points. |
rpki.cloudflare.com |
Validate ROA registration and propagation status. |
stat.ripe.net |
RIPE routing visibility and prefix visibility stats. |
bgptunnel.com portal |
Manage iFog WireGuard tunnels, check tunnel state. |
route64.org portal |
Manage ROUTE64 tunnels, check session state. |
t-mobile.com/home-internet |
Coverage check before ordering ISP-B. |
Annual Cost Summary
| Item | One-time | Annual |
|---|---|---|
RIPE ASN — €50 NCC fee + Voldeta margin |
~€60 |
~€60 |
RIPE PI /48 IPv6 — €50 NCC fee + Voldeta margin |
~€60 |
~€70 |
iFog BGPTunnel transit |
Free |
Free |
ROUTE64 transit |
Free |
Free |
T-Mobile 5G Home Internet |
— |
~$600 |
ISP-A wired circuit |
— |
existing |
Total new spend |
~€120 (~$130) |
~$730/yr |
Professional Portfolio Use
This document demonstrates production-grade network architecture skills suitable for interview portfolios and professional discussions.
Skills Demonstrated
| Skill Area | Evidence in This Document |
|---|---|
BGP Operations |
eBGP multihoming, route maps, local-preference, AS-path prepending, RPKI/ROA validation, IRR object creation |
Traffic Engineering |
Active-active inbound split via prepending, outbound preference via local-pref, per-upstream policy differentiation |
High Availability |
Dual physical circuits, dual BGP upstreams, dual VyOS nodes, VRRP split-master, conntrack-sync for session preservation |
Fast Convergence |
BFD with per-transport tuning (wired vs cellular), aggressive BGP hold timers, sub-second failure detection |
Enterprise Patterns |
VRF for WAN separation (not policy routing), graceful shutdown for maintenance, dual-stack with NAT44 + native IPv6 |
Infrastructure Planning |
Hardware prerequisites, cost analysis, procurement sequencing, failure mode analysis, verification procedures |
Internet Governance |
RIPE NCC process, LIR sponsorship model, IRR/RPKI ecosystem understanding, provider-independent address space |
Target Roles
| Role Level | Relevance |
|---|---|
Mid-Level Network Engineer |
Demonstrates readiness for senior responsibilities. Direct skill match. |
Senior Network Engineer |
Good conversation starter. Expect probing questions on design decisions. |
Network Architect |
Shows end-to-end thinking: physical layer through BGP policy through failure scenarios. |
ISP / Transit Provider |
Direct relevance. This is core ISP edge work at smaller scale. |
Cloud Network Engineer |
Demonstrates understanding of what cloud abstracts away. Valuable context. |
Positioning in Interviews
|
What to say
"I designed this for my home enterprise infrastructure. The document covers procurement through implementation through failure testing. I wanted real BGP multihoming experience with actual transit providers, not just lab simulations. The architecture uses provider-independent IPv6 space from RIPE, dual physical last-mile circuits, and active-active forwarding across two VyOS nodes." |
Likely Interview Questions
| Question | Key Points |
|---|---|
"Why RIPE instead of ARIN?" |
ARIN has multi-year waitlists, expensive for small allocations. RIPE sponsors non-EU members, faster processing, cost-effective for IPv6-only PI space. |
"Why two BGP upstreams?" |
Single upstream = provider lock-in, no failover path, no traffic engineering practice. Dual upstream enables active-active and real-world failure scenarios. |
"What if both physical ISPs fail?" |
Total outage. Acceptable risk for home infrastructure. The design documents the failure domain explicitly — shows realistic thinking. |
"Why not cloud provider BGP (AWS, GCP)?" |
Cloud BGP is abstracted — you don’t see the PE, don’t control timers, don’t manage IRR/RPKI. This is raw BGP with real upstream routers. Different skill set. |
"Have you implemented this?" |
Answer honestly: "In procurement phase" or "Running in production." Either is valid — the design work itself demonstrates the skill. |
"Why T-Mobile 5G for redundancy?" |
Cheapest genuine physical diversity in US consumer market. Separate infrastructure from wired (cellular towers vs cable/fiber plant). CGNAT doesn’t affect outbound WireGuard tunnels. |
What Differentiates This
Most candidates discuss BGP from certification study or GNS3 labs. This document demonstrates:
-
Real design with real providers (iFog, ROUTE64, Voldeta/RIPE)
-
Real cost analysis and procurement planning
-
Real failure mode thinking with recovery mechanisms
-
Actual implementation intent, not theoretical exercise
The difference between "I studied BGP" and "I designed and will operate a multihomed AS" is significant in hiring decisions.
Appendix: Port Discovery Scripts
Quick Port Status
# Port status with bridge membership and link state
ip -br link show | awk '/^(eno|br-)/ {printf "%-12s %-10s %s\n", $1, $2, $3}'
# Which ports are in which bridges
bridge link show | awk '{print $2, "→", $NF}'
Comprehensive Port Inventory
# Full picture: port, state, speed, bridge membership
for port in eno{1..8}; do
state=$(cat /sys/class/net/$port/operstate 2>/dev/null || echo "missing")
speed=$(cat /sys/class/net/$port/speed 2>/dev/null || echo "?")
master=$(ip link show $port 2>/dev/null | awk -F'master ' '{print $2}' | awk '{print $1}')
printf "%-6s %-6s %5sMbps %s\n" "$port" "$state" "$speed" "${master:-[none]}"
done