fix(vlans): robust bridge-IP removal; record cutover + gotchas

RouterOS 'find ... address=<prefix>' never matches an ip/address value, so the
legacy-bridge-IP removal is now a :foreach get-and-compare. Refresh the committed
export.rsc to the post-cutover config (flat VLAN 30 + isolated mgmt VLAN 99 on
ether8, vlan-filtering on). Spec updated with execution notes (NM autoconnect flap,
the find-address quirk, and the commit-confirmed detached-flip technique used).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
sjat 2026-06-09 12:38:04 +02:00
parent ebd21623ef
commit 199edf85ad
3 changed files with 44 additions and 22 deletions

View file

@ -1,26 +1,30 @@
# 2025-09-11 09:49:07 by RouterOS 7.19.6 # 2025-09-11 10:03:39 by RouterOS 7.19.6
# software id = 73S3-5F2W # software id = 73S3-5F2W
# #
# model = CRS310-8G+2S+ # model = CRS310-8G+2S+
# serial number = HM40B8TDNDD # serial number = HM40B8TDNDD
/interface bridge /interface bridge
add admin-mac=D0:EA:11:24:F4:AA auto-mac=no comment=defconf name=bridge add admin-mac=D0:EA:11:24:F4:AA auto-mac=no comment=defconf name=bridge \
vlan-filtering=yes
/interface vlan
add interface=bridge name=vlan-mgmt vlan-id=99
/interface bridge port /interface bridge port
add bridge=bridge comment=defconf interface=ether1 add bridge=bridge comment=defconf interface=ether1 pvid=30
add bridge=bridge comment=defconf interface=ether2 add bridge=bridge comment=defconf interface=ether2 pvid=30
add bridge=bridge comment=defconf interface=ether3 add bridge=bridge comment=defconf interface=ether3 pvid=30
add bridge=bridge comment=defconf interface=ether4 add bridge=bridge comment=defconf interface=ether4 pvid=30
add bridge=bridge comment=defconf interface=ether5 add bridge=bridge comment=defconf interface=ether5 pvid=30
add bridge=bridge comment=defconf interface=ether6 add bridge=bridge comment=defconf interface=ether6 pvid=30
add bridge=bridge comment=defconf interface=ether7 add bridge=bridge comment=defconf interface=ether7 pvid=30
add bridge=bridge comment=defconf interface=ether8 add bridge=bridge comment=defconf interface=ether8 pvid=99
add bridge=bridge comment=defconf interface=sfp-sfpplus1 add bridge=bridge comment=defconf interface=sfp-sfpplus1 pvid=30
add bridge=bridge comment=defconf interface=sfp-sfpplus2 add bridge=bridge comment=defconf interface=sfp-sfpplus2 pvid=30
/interface bridge vlan
add bridge=bridge untagged="ether1,ether2,ether3,ether4,ether5,ether6,ether7,s\
fp-sfpplus1,sfp-sfpplus2" vlan-ids=30
add bridge=bridge tagged=bridge untagged=ether8 vlan-ids=99
/ip address /ip address
add address=192.168.88.1/24 comment=defconf interface=bridge network=\ add address=192.168.88.1/24 interface=vlan-mgmt network=192.168.88.0
192.168.88.0
/ip dns
set servers=10.0.99.1
/ip service /ip service
set ftp disabled=yes set ftp disabled=yes
set telnet disabled=yes set telnet disabled=yes
@ -29,7 +33,5 @@ set api disabled=yes
set api-ssl disabled=yes set api-ssl disabled=yes
/system identity /system identity
set name=crs310-maker set name=crs310-maker
/system ntp client
set enabled=yes
/system ntp client servers /system ntp client servers
add address=10.0.99.1 add address=10.0.99.1

View file

@ -91,6 +91,25 @@ all-access topology (DATA untagged = data ports, CPU tagged only on MGMT).
- **Removing the legacy bridge IP** is the delicate step — done while the new - **Removing the legacy bridge IP** is the delicate step — done while the new
`vlan-mgmt` IP is the same address, before filtering, with the connection watched. `vlan-mgmt` IP is the same address, before filtering, with the connection watched.
## Execution notes (applied 2026-06-09)
Cutover completed; switch is VLAN-filtered with isolated mgmt reachable on `ether8`.
`play_switch.yml` runs idempotently over the new mgmt path. Two gotchas surfaced:
- **NetworkManager autoconnect flap:** moving mamba's cable bounced the link; NM
re-selected the DHCP profile and dropped the static mgmt IP. Fixed by making
`crs310-bench` (192.168.88.2) sticky (`autoconnect yes`, priority 10) and turning
`autoconnect off` on `Wired connection 1`.
- **RouterOS `find ... address=<prefix>` never matches** an `/ip/address` value (returns
0 even on an exact string). The first flip therefore failed to remove the defconf IP
off `bridge`, duplicating `192.168.88.1` onto `vlan-mgmt` and breaking ARP. Fix: remove
by `[find interface=bridge]`, or match via `:foreach`+`/ip/address/get $a address`.
- **The flip was run as a detached, self-reverting on-device job** (`:execute { … :delay
240s; :if ($mgmtok=false) do={ revert } }`) — a commit-confirmed pattern. The first
(failed) attempt auto-healed at the timer; the corrected attempt was confirmed by
setting `:global mgmtok true` within the window. Recommended for any future
`vlan-filtering`/mgmt-IP change made over the network.
## Out of scope ## Out of scope
Real inter-VLAN segmentation, the SFP+ 10G uplink/trunk, and any upstream router VLAN Real inter-VLAN segmentation, the SFP+ 10G uplink/trunk, and any upstream router VLAN

View file

@ -82,13 +82,14 @@
# detached flip (see the design doc's runbook), not by a straight play run. In steady # detached flip (see the design doc's runbook), not by a straight play run. In steady
# state both tasks below are no-ops. # state both tasks below are no-ops.
- name: Remove the legacy management IP from the bare bridge interface - name: Remove the legacy management IP from the bare bridge interface
# NOTE: RouterOS `find ... address=<v>` does NOT match an ip/address prefix value
# (it returns 0 even on an exact string), so match by get-and-compare instead.
community.routeros.command: community.routeros.command:
commands: commands:
- >- - >-
:if ([:len [/ip/address/find interface="{{ switch_bridge_name }}" :foreach a in=[/ip/address/find interface="{{ switch_bridge_name }}"]
address="{{ switch_mgmt_address }}"]] > 0) do={ :if ([/ip/address/get $a address]="{{ switch_mgmt_address }}")
do={ /ip/address/remove [find interface="{{ switch_bridge_name }}" do={ /ip/address/remove $a } }
address="{{ switch_mgmt_address }}"] }
changed_when: false changed_when: false
- name: Assign the management IP address to vlan-mgmt - name: Assign the management IP address to vlan-mgmt