feat(labsim): add WAN transport VLANs so the sim can host fake ISPs

A cutover attempt failed on the WAN and nothing had tested it. The reason the
sim could not have caught it: labsim modelled every LAN VLAN faithfully and
omitted the WAN entirely -- vlans.conf had 1, 2, 3, 9, 10 and 200, never 51 or
53. Worse, the switch script's WAN health checks are conditional on the delta
configuring PPPoE, so in the sim they printed "this delta configures no WAN --
skipping all WAN health checks" and passed. The sim proved the delta commits; it
never proved the WAN works, and could not have.

Adds VLANs 51 (Vodafone/PPPoE) and 53 (10gig/DHCP) to the fabric so a fake ISP
can live on each and those checks actually execute. VyOS has service
pppoe-server (accel-ppp) natively -- authentication local-users, client-ip-pool,
gateway-address -- so a VyOS VM can play the concentrator, and dhcp-server can
play the other ISP.

vlans.conf gains host_octet 0, meaning "no host leg". A host address on a WAN
transport VLAN would misrepresent the segment: the point is that VyOS reaches an
ISP, not the host.

Also fixes a real gap in ovs_bond_router: it returned early when the bond
already existed, so adding a VLAN to vlans.conf never reached an existing bond.
Re-runs now reconcile the trunk and say so. That gap is the same SHAPE as the
production failure -- interface present, VLAN missing from the trunk, frames
silently dropped -- which is precisely the class of bug the sim needs to be able
to reproduce rather than embody.

Both bonds updated: [2,3,9,10,200] -> [2,3,9,10,51,53,200].

Note on the production diagnosis, which is NOT settled: a passive RX test showed
zero frames on 51/53 at the firewall, and an active DHCP DISCOVER (verified to
have transmitted, tx +2) drew no reply. That is consistent with the VLANs not
being trunked, but equally with the ISP only answering its registered CPE MAC --
which is exactly why the delta clones f0:9f:c2:12:9b:4f, and why it cannot be
settled from production while the USG holds that MAC.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DMVzWZgiKW2wquf5z8S1yH
This commit is contained in:
Michal
2026-08-18 00:44:11 +01:00
parent 41b5448f56
commit ee070371a8
2 changed files with 29 additions and 3 deletions

View File

@@ -49,7 +49,12 @@ ovs_up() {
# Drop any address from a previous mask/octet so a changed vlans.conf does
# not leave a stale second address on the port.
sudo ip -4 addr flush dev "$port" 2>/dev/null || true
sudo ip addr replace "${V_PREFIX}.${V_HOST}/${V_MASK}" dev "$port"
# host_octet 0 means "no host leg": the WAN transport VLANs belong to the
# fake ISPs, and giving the host an address there would misrepresent the
# segment -- the whole point is that VyOS reaches an ISP, not the host.
if [ "$V_HOST" != "0" ]; then
sudo ip addr replace "${V_PREFIX}.${V_HOST}/${V_MASK}" dev "$port"
fi
done
ovs_define_libvirt_net
@@ -117,9 +122,19 @@ ovs_bond_router() {
local count; count="$(echo "$taps" | grep -c .)"
[ "$count" -eq 2 ] || { warn "router $vm has $count tap(s), expected 2 — skipping bond"; return 1; }
# Already bonded? (idempotent re-runs)
# Already bonded? Re-runs must still reconcile the VLAN list: adding a VLAN to
# vlans.conf and finding the bond unchanged is exactly how a VLAN silently
# fails to reach a router -- interface present, tag missing, frames dropped by
# the switch. Returning early here once cost real debugging time.
if ovs list-ports "$OVS_BR" 2>/dev/null | grep -qx "$LAG_NAME"; then
log "LACP bond $LAG_NAME already present"
local want; want="$(vlan_id_list | tr ',' '\n' | grep -vx 1 | paste -sd, -)"
local have; have="$(ovs get port "$LAG_NAME" trunks 2>/dev/null | tr -d '[] ')"
if [ "$want" != "$have" ]; then
log "bond $LAG_NAME trunk drift: [$have] -> [$want]; updating"
ovs set port "$LAG_NAME" trunks="$want"
else
log "LACP bond $LAG_NAME already present, trunk correct"
fi
return 0
fi

View File

@@ -30,3 +30,14 @@
9:private:172.31.9:10.0.9.0/23
10:lot:172.31.10:10.0.0.0/23:23:3
200:roomates:172.31.200:192.168.2.0/24
# WAN transport VLANs, mirroring production. These exist so the sim can run a
# fake ISP on each and the switch script's WAN health checks actually execute
# instead of printing "this delta configures no WAN -- skipping". A cutover
# attempt failed on the WAN with nothing having tested it, because the sim
# modelled every LAN VLAN faithfully and omitted the WAN entirely.
#
# No host leg is wanted here (host_octet 0 means "skip"): the ISP VMs own these
# segments, and a host address on a WAN transport VLAN would be a lie.
51:wan1:172.31.51:vodafone-pppoe(VLAN 51):24:0
53:wan3:172.31.53:10gig-dhcp(VLAN 53):24:0