13 KiB
edge → RouterOS 7 upgrade runbook
Edge is a CCR2004-1G-12S+2XS currently on 6.49.18 (the only ROS6 box left in
the fleet). The auto-converter handles /ip firewall, /ip address,
/ip route, /interface, /snmp, /system, and most NAT correctly. The
following areas need manual pre-staging because the ROS7 converter either
silently drops them or rewrites them into dead code:
/routing filter→/routing filter rule(BGP/OSPF filter chains)/routing bgp instance+/routing bgp peer→/routing bgp instance+/routing bgp template+/routing bgp connection/routing ospf instance+/routing ospf interface+/routing ospf nbma-neighbor→/routing ospf instance+/routing ospf area+/routing ospf interface-template+/routing ospf static-neighbor/routing bfd interface→/routing bfd configuration/mpls ldpset →/mpls ldpadd +/mpls ldp interface/routing rip(delete entirely)
Reference for ROS7 conventions: core.rsc, climax.rsc.
0. Pre-flight (before touching the router)
# from your workstation
cd /Users/graham/dev/network/mikrotik-tool
./mikrotik-tool export # snapshot fresh /export
cp edge.rsc edge.rsc.pre-ros7-$(date +%F) # keep the ROS6 baseline
Verify console/out-of-band access (Spectrum link on sfp-sfpplus12 is the
WAN — if BGP doesn't come back, you lose remote access via that path; iBGP
to core via preseem is the management fallback).
Confirm OSPF auth shared key from one of the peers (climax or core) so the
new /routing ospf interface-template can be configured with matching auth.
Edge's ROS6 export doesn't include the secret.
1. Stage One: in-place fixes on ROS6 (optional cleanups)
These are pure ROS6 commands you can run now to reduce churn during the upgrade.
# Normalize mpls-mtu to fleet standard 1508 (currently 1530)
/mpls interface
set [find interface=sfp-sfpplus8-server-switch] mpls-mtu=1508
set [find default=yes] mpls-mtu=1508
# Add IPv4 anchor for BGP origination
# In ROS6, /routing bgp network injects 204.110.188.0/22 directly.
# In ROS7, we need the prefix to exist in the routing table for it to be
# advertised. Adding the anchor now is harmless on ROS6.
/ip route
add dst-address=204.110.188.0/22 type=blackhole distance=200 \
comment="anchor for BGP origination to TWC (ROS7 needs RIB entry)"
2. Upgrade to RouterOS 7
# On the router (Winbox/SSH):
/system package update
set channel=long-term
check-for-updates
# verify it offers 7.21.4 (the fleet standard, see CLAUDE.md fleet topology)
install
# router reboots
After reboot, verify version and that interfaces came back:
/system resource print
/interface print
/ip address print
OSPF/BGP will be broken at this point — the auto-converter has run but filter chains, BGP connections, and OSPF templates are either missing or wrong. Static routes still work, so the Spectrum default + the static backbones to climax keep the box reachable.
3. Clear the auto-converted garbage
# BGP - remove auto-converted artifacts
/routing bgp connection
remove [find]
/routing bgp template
remove [find name!=default]
# OSPF - remove auto-converted artifacts
/routing ospf interface-template
remove [find]
/routing ospf static-neighbor
remove [find]
/routing ospf area
remove [find name!=backbone]
/routing ospf instance
remove [find name!=default-v2]
# Filter chains - remove anything auto-converted
/routing filter rule
remove [find]
# LDP - remove auto-converted artifacts
/mpls ldp interface
remove [find]
/mpls ldp
remove [find]
# BFD - remove auto-converted artifacts
/routing bfd configuration
remove [find]
# RIP - delete it, never coming back
/routing rip
# (RIP package is not installed by default on ROS7, may already be gone)
# Old BGP network announcements (replaced by RIB anchor + filter chain)
/routing bgp network
remove [find] # if the menu still exists in your ROS7 build
4. Stage the ROS7 routing config
4a. Routing IDs and instances
/routing id
add disabled=no id=10.254.254.254 name=id-1 select-dynamic-id=""
/routing bgp instance
add as=393837 cluster-id=10.254.254.254 name=bgp-instance-1 \
router-id=10.254.254.254
/routing bgp template
set default as=393837 disabled=no
/routing ospf instance
add disabled=no in-filter-chain=ospf-in name=default-v2 \
out-filter-chain=ospf-out redistribute=connected,static \
router-id=id-1 routing-table=main \
originate-default=always
/routing ospf instance
add disabled=no in-filter-chain=ospf-in name=default-v3 \
out-filter-chain=ospf-out redistribute=connected,static \
router-id=id-1 routing-table=main version=3 \
originate-default=always
/routing ospf area
add disabled=no instance=default-v2 name=backbone-v2
add disabled=no instance=default-v3 name=backbone-v3
4b. Filter chains (THE default-deny fix)
Auto-converter does NOT bridge these — must be added explicitly and referenced from the instances/connections.
/routing filter rule
# OSPF: accept everything in both directions
add chain=ospf-in disabled=no rule="accept"
add chain=ospf-out disabled=no rule="accept"
# eBGP to TWC: inbound = default route only
add chain=twc-in disabled=no rule=\
"if (dst==0.0.0.0/0 && dst-len==0) { accept } else { reject }"
# eBGP to TWC: outbound = only our /22 and our v6 /32
add chain=twc-out disabled=no rule=\
"if ((dst==204.110.188.0/22 && dst-len==22) || (dst==2606:1c80::/32 && dst-len==32)) { accept } else { reject }"
# iBGP-RR (v6 transport, v4+v6 NLRI): RR client filters
add chain=v6-rr-in disabled=no rule=\
"if (dst==0.0.0.0/0 || dst==::/0 || dst-len==44 || dst-len==64 || dst-len==128) { accept } else { reject }"
add chain=v6-rr-out disabled=no rule=\
"if (dst==0.0.0.0/0 || dst==::/0 || dst-len==44 || dst-len==64 || dst-len==128) { accept } else { reject }"
Note: dst-len==44 covers per-tower IPv6 allocations, ==64 covers
per-link/server LANs, ==128 covers loopbacks. Adjust if your v6 plan in
ipv6.md uses different prefix lengths.
4c. BGP connections
/routing bgp connection
# eBGP to TWC, v4
add disabled=no afi=ip as=393837 name=twc \
instance=bgp-instance-1 \
local.address=71.41.226.118 \
remote.address=71.41.226.117 .as=11427 \
input.filter=twc-in \
output.filter-chain=twc-out \
output.network=204.110.188.0/22 \
output.redistribute=""
# eBGP to TWC, v6
add disabled=no afi=ipv6 as=393837 name=twc-v6 \
instance=bgp-instance-1 \
local.address=2605:6000:0:8::f:373 \
remote.address=2605:6000:0:8::f:372 .as=11427 \
input.filter=twc-in \
output.filter-chain=twc-out \
output.network=2606:1c80::/32 \
output.redistribute=""
# iBGP-RR to core (v4+v6 NLRI over v6 transport, edge is the RR)
add disabled=no afi=ip,ipv6 as=393837 \
comment="iBGP-RR to core" \
instance=bgp-instance-1 \
local.address=2606:1c80:0:10::254 .role=ibgp-rr \
remote.address=2606:1c80:0:10::253 .as=393837 \
multihop=yes \
nexthop-choice=force-self \
input.filter=v6-rr-in \
output.filter-chain=v6-rr-out \
output.redistribute=connected,static,ospf \
output.default-originate=always \
name=ibgp-rr-core
If/when you add more RR clients (climax, culleoka, etc. peering directly to
edge), they each get their own /routing bgp connection block mirroring the
ibgp-rr-core pattern with .role=ibgp-rr on edge's side.
4d. OSPF interface templates and static neighbors
Replicate the per-interface settings from the old /routing ospf interface
block. Adjust auth values to match the rest of the fleet (verify shared
key from climax or core first).
/routing ospf interface-template
# Preseem (primary path to core) - wired, BFD on
add disabled=no area=backbone-v2 auth-id=1 cost=10 \
interfaces=sfp-sfpplus11-preseem priority=1 type=ptp use-bfd=yes
# Direct backup to core - wired, BFD on
add disabled=no area=backbone-v2 auth-id=1 cost=100 \
interfaces=sfp-sfpplus7-core-direct priority=1 type=ptp use-bfd=yes
# Server switch VLAN9 (loopback / server LAN)
add disabled=no area=backbone-v2 \
interfaces=sfp-sfpplus8-server-switch type=broadcast
add disabled=no area=backbone-v2 passive=yes \
interfaces=vlan9_sfpplus8 type=broadcast
# Spectrum WAN - passive (we don't run OSPF to TWC)
add disabled=no area=backbone-v2 passive=yes \
interfaces=sfp-sfpplus12-spectrum type=broadcast
# IPv6 area equivalents on the same wired links
add disabled=no area=backbone-v3 cost=10 \
interfaces=sfp-sfpplus11-preseem type=ptp use-bfd=yes
add disabled=no area=backbone-v3 cost=100 \
interfaces=sfp-sfpplus7-core-direct type=ptp use-bfd=yes
add disabled=no area=backbone-v3 \
interfaces=sfp-sfpplus8-server-switch type=broadcast
/routing ospf static-neighbor
# Core (preseem path)
add disabled=no area=backbone-v2 \
address=204.110.191.185%sfp-sfpplus11-preseem
# Core (direct path) - if you want OSPF on this link as a hot standby
add disabled=no area=backbone-v2 \
address=204.110.191.181%sfp-sfpplus7-core-direct
Do not add the old NBMA neighbors 10.250.1.94, 10.250.1.57,
10.250.1.201, 10.250.2.1 — those were stale wireless backbone
neighbors that don't apply to edge (edge has no wireless backbone links).
4e. BFD
/routing bfd configuration
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5 \
vrf=main
Per the fleet note in CLAUDE.md, BFD on wireless backbone links is problematic — edge has none, so this global config is fine.
4f. MPLS / LDP
/mpls interface
# (mpls-mtu was already set in stage 1, but verify)
set [find interface=sfp-sfpplus7-core-direct] mpls-mtu=1508
set [find interface=sfp-sfpplus11-preseem] mpls-mtu=1508
set [find interface=sfp-sfpplus8-server-switch] mpls-mtu=1508
/mpls ldp
add disabled=no lsr-id=10.254.254.254 \
transport-addresses=10.254.254.254 vrf=main
/mpls ldp interface
add interface=sfp-sfpplus7-core-direct
add interface=sfp-sfpplus11-preseem
add interface=sfp-sfpplus8-server-switch
LDP accept/advertise filtering: the ROS6 export was set to only advertise
the loopback /32 (/mpls ldp advertise-filter add prefix=10.254.254.254/32
add advertise=no). If you want to preserve that behavior, add a filter chain:
/routing filter rule
add chain=ldp-advertise disabled=no rule=\
"if (dst==10.254.254.254/32 && dst-len==32) { accept } else { reject }"
# Reference from /mpls ldp - syntax varies by ROS7 version, check
# /mpls ldp print detail after adding the rule
For most fleets this is over-engineering — LDP advertising all loopbacks is normally fine. Skip unless you have a specific reason.
5. Verification
# Interfaces and addressing
/interface print
/ip address print
# OSPF adjacencies
/routing ospf neighbor print
# expect: core via sfp-sfpplus11-preseem (Full), optionally
# core via sfp-sfpplus7-core-direct (Full)
# OSPF routes
/ip route print where ospf
/ipv6 route print where ospf
# BGP sessions
/routing bgp session print
# expect: twc (Established), twc-v6 (Established), ibgp-rr-core (Established)
# BGP advertisements to TWC
/routing bgp advertisements print peer=twc
# expect: 204.110.188.0/22 advertised
/routing bgp advertisements print peer=twc-v6
# expect: 2606:1c80::/32 advertised
# BGP routes received
/routing route print where bgp
# expect: 0.0.0.0/0 from TWC v4, ::/0 from TWC v6, plus customer prefixes
# from iBGP-RR
# LDP sessions
/mpls ldp neighbor print
# expect: session to core via direct + preseem links
# LDP-installed labels
/mpls forwarding-table print
# BFD sessions
/routing bfd session print
# expect: up to core via preseem and direct
# Full reachability check
/ping 10.254.254.253 # core loopback
/ping 10.254.254.101 # verona loopback
/tool traceroute 10.254.254.102 src-address=10.254.254.254 # to climax via MPLS
6. If things go wrong
The Spectrum default route (/ip route add distance=1 gateway=71.41.226.117)
and the manually-pinned statics in /ip route (lines 508-531 of the old
export) keep edge reachable from the Internet even without BGP/OSPF. From
inside the network, the static 204.110.191.182/30 link to core stays up
and is OSPF-independent.
Rollback path: /system package downgrade with the prior 6.49.18 npk
available in the file store. Keep edge.rsc.pre-ros7-<date> around to
re-paste any pieces the upgrade mangles unrecoverably.
7. Post-upgrade cleanup
# back on the workstation
cd /Users/graham/dev/network/mikrotik-tool
./mikrotik-tool export # fresh edge.rsc on ROS7
git add edge.rsc edge-upgrade.md
git commit -m "edge: ROS7 upgrade"
Update CLAUDE.md to remove the "Edge runs ROS 6.49.18 (legacy, no MPLS, ignore for the spine)" note once edge is fully on ROS7 with MPLS in the spine.