# =============================================================================
# edge — IPv6 apply script (ROS 6.49.18, BGP-only / no OSPFv3)
# =============================================================================
#
# Edge is the iBGP hub: it terminates the TWC v6 eBGP peering and the v4
# transport iBGP sessions to every tower. v6 NLRI rides v4 transport (so the
# existing v4 OSPF reachability between loopbacks is reused; no v6 IGP is
# needed). This matches the verona-v6-apply.rsc design choice.
#
# Two paths edge<->core:
#   1. PRIMARY: sfp-sfpplus11-preseem via the Preseem shaper (transparent
#      L2). OSPFv2 cost on edge is the default 10. v6 P2P:
#      2606:1c80:0:1002::/64 (edge .1, core .2)
#   2. BACKUP: sfp-sfpplus7-core-direct direct fiber. OSPFv2 cost on edge
#      is 100 (same on core's side). v6 P2P:
#      2606:1c80:0:11::/64 (edge .1, core .2)
# NOTE: P2P prefix is /64 not /127 — picking ::1/127 + ::2/127 puts the
# two ends in *different* /127 networks (verified live 2026-05-09). /64
# matches the per-link allocation in ipv6.md.
# Static v6 routes for the infra /48 mirror that cost relationship by
# distance (lower = preferred): preseem at distance=1, direct at
# distance=2.
#
# What this script DOES NOT touch (USER CONSTRAINT 2026-05-09):
#   * TWC v6 eBGP peer `twc-v6` (remote 2605:6000:0:8::f:372, AS11427) —
#     name doesn't match the ^ibgp- wipe pattern, so it survives.
#   * The 2606:1c80::/32 BGP network announcement upstream.
#   * The TWC P2P address 2605:6000:0:8::f:373/127 on sfp-sfpplus12-spectrum
#     — enabled, so it survives the [find disabled=yes] wipe.
#   * The existing server LAN address 2606:1c80::1 on vlan9_sfpplus8 —
#     enabled, so it survives. We only ADD a per-interface ND override
#     to suppress RA there; the IP and prefix are unmodified.
#   * v4 OSPFv2 / RIP / firewall rules — v4 control plane is unchanged.
#
# Apply order: review -> paste in winbox/SSH on edge -> verify with checks
# at the bottom -> only then run the matching `core-v6-apply.rsc` so the
# preseem and direct /127 endpoints come up symmetrically.
# =============================================================================

# -----------------------------------------------------------------------------
# WIPE — only the stale internal-only v6 state on edge. Leaves TWC peering,
# the upstream /32 announcement, the server LAN address, and v4 alone.
# -----------------------------------------------------------------------------
# Drop any disabled placeholder v6 internal addresses (none on edge today,
# but harmless if present).
/ipv6 address remove [find disabled=yes]

# Drop any leftover OSPFv3 interface entries (we are committing to BGP-only
# for v6; any v3 instances on edge have been minimal/stub).
/routing ospf-v3 interface remove [find]

# Drop only internal iBGP v6 peers if any exist; never touch twc-v6.
/routing bgp peer remove [find name~"^ibgp-" and address-families~"ipv6"]

# -----------------------------------------------------------------------------
# APPLY — addresses
# -----------------------------------------------------------------------------
/ipv6 settings set forward=yes accept-router-advertisements=no

/ipv6 address
add address=2606:1c80:0:10::254/128 interface=loopback advertise=no comment="edge loopback"
add address=2606:1c80:0:11::1/64   interface=sfp-sfpplus7-core-direct advertise=no comment="P2P edge<->core direct (backup)"
add address=2606:1c80:0:1002::1/64 interface=sfp-sfpplus11-preseem    advertise=no comment="P2P edge<->core via preseem (primary)"

# NOTE: the server LAN address 2606:1c80::1 on vlan9_sfpplus8 is left
# untouched per user constraint. The ND override below makes it RA-free
# without modifying the address itself.

# -----------------------------------------------------------------------------
# APPLY — neighbour discovery: SUPPRESS RA on the server LAN
# -----------------------------------------------------------------------------
# Server LAN is static-only per the IPv6 plan — disable RA + DHCPv6 hints.
# A per-interface entry overrides the global default.
/ipv6 nd
add interface=vlan9_sfpplus8 disabled=no advertise=no managed-address-configuration=no other-configuration=no comment="server LAN: static only, no SLAAC"

# -----------------------------------------------------------------------------
# APPLY — static routes (replace what an IGP would have learned)
# -----------------------------------------------------------------------------
# Infra /48 covers all router loopbacks (2606:1c80:0:10::/64), all P2P
# /64s, and any future infra slots. Two entries with different distances
# pin preseem as primary and direct as backup. The connected /64 server
# LAN at 2606:1c80::/64 wins by longest-prefix-match, so this /48 doesn't
# steal local server traffic.
/ipv6 route
add dst-address=2606:1c80::/48 gateway=2606:1c80:0:1002::2 distance=1 comment="infra: via preseem (primary)"
add dst-address=2606:1c80::/48 gateway=2606:1c80:0:11::2   distance=2 comment="infra: via direct (backup)"

# Tower /44s are learned via iBGP from each tower (next-hop = tower's v6
# loopback inside :10::/64, recursively resolved through the /48 above).
# No static needed for them.

# -----------------------------------------------------------------------------
# APPLY — firewall (extend the existing minimal v6 ruleset)
# -----------------------------------------------------------------------------
# The existing v6 firewall already accepts BGP (179) and established. Add
# the rules required for internal-network forwarding + ICMPv6 / link-local.
/ipv6 firewall filter
add chain=input  action=accept protocol=icmpv6                  comment="icmpv6 input"
add chain=input  action=accept src-address=fe80::/10            comment="link-local input"
add chain=input  action=accept src-address=2606:1c80::/32       comment="internal input"

add chain=forward action=accept protocol=icmpv6 hop-limit=equal:1 comment="PMTUD forward"
add chain=forward action=accept protocol=icmpv6                   comment="icmpv6 forward"
add chain=forward action=accept src-address=2606:1c80::/32 dst-address=2606:1c80::/32 comment="internal<->internal"

# (we do not add a default-deny; edge has long-running customer transit
# paths and a sudden v6 default-deny would break them. existing rules at
# the bottom of /ipv6 firewall filter remain authoritative.)

# -----------------------------------------------------------------------------
# APPLY — iBGP route filters (v6)
# -----------------------------------------------------------------------------
# Edge has ONE iBGP v6 peer: core, which is the v6 RR for the fleet. Edge is
# an RR client of core (no `route-reflect=yes` — that flag would mark the
# OTHER side as a client, but edge has no clients). Edge sends ::/0 to core
# (which reflects it to towers) and learns tower /44s + /128 loopbacks from
# core (reflected from each tower).
#
# in-filter: accept any infra/customer prefix that core (v6 RR) reflects to
# us. Length 44 = customer aggregates, 64 = backbone P2Ps + per-tower LAN /64s,
# 128 = router loopbacks. Anything else within 2606:1c80::/32 is rejected
# (defense in depth — keeps random connected /80 etc. from leaking).
/routing filter
add chain=ibgp-rr-in   prefix=2606:1c80::/32 prefix-length=44-128 action=accept comment="any reflected infra/customer prefix"
add chain=ibgp-rr-in   action=discard                                            comment="default deny"

# out-filter: edge sends only the v6 default to core (which the RR fans
# out to every tower). Anything else stays inside edge.
add chain=ibgp-rr-out  prefix=::/0  prefix-length=0  action=accept comment="default route"
add chain=ibgp-rr-out  action=discard                              comment="default deny"

# -----------------------------------------------------------------------------
# APPLY — iBGP peer to core (v6 transport, carrying v6 NLRI)
# -----------------------------------------------------------------------------
# v6 transport (loopback-to-loopback over 2606:1c80:0:10::254 ↔ ::253) avoids
# the v4-mapped-next-hop bug we hit with v4 transport carrying v6 NLRI. Core
# (ROS7) is the route reflector — edge is an RR client and, importantly, NOT
# a reflector itself (ROS 6.49 does not properly reflect v6 NLRI even with
# all RR settings; that's the entire reason core has the role).
# update-source=loopback sources the TCP session from edge's loopback iface
# (which holds both 10.254.254.254 and 2606:1c80:0:10::254).
# nexthop-choice=force-self pins the next-hop edge advertises (::/0) to
# edge's own v6 loopback so towers can resolve it via the RR-reflected
# /128 path.
/routing bgp peer
add name=ibgp-rr-core remote-address=2606:1c80:0:10::253 remote-as=393837 update-source=loopback address-families=ipv6 nexthop-choice=force-self ttl=255 in-filter=ibgp-rr-in out-filter=ibgp-rr-out default-originate=always comment="iBGP to core (v6 RR), v6 transport"

# -----------------------------------------------------------------------------
# VERIFY (paste after apply)
# -----------------------------------------------------------------------------
# /ipv6 address print
# /ipv6 route print where active
# /ipv6 nd print
# /routing bgp peer print where name~"v6"
# /routing bgp advertisements print peer=ibgp-verona-v6
#
# Expected immediately:
#   * /ipv6 address print  shows 2606:1c80:0:10::254/128 (loopback),
#     :11::1/127 (direct), :1002::1/127 (preseem), :1::/64 server LAN
#   * /ipv6 nd print  shows the vlan9_sfpplus8 entry with advertise=no
#   * the new /48 routes show as inactive (gateway unreachable until core
#     applies), which is fine
#   * ibgp-verona-v6 is in `connecting` state until verona reaches edge's
#     v6 loopback (which needs core configured) — for the bare TCP
#     session, v4 loopback reachability is enough so the session SHOULD
#     come up immediately. confirm with /routing bgp peer print.
#
# Once core has its matching v6 apply:
#   /ping 2606:1c80:0:1002::2 count=3   ;; core preseem-side
#   /ping 2606:1c80:0:11::2 count=3     ;; core direct-side
#   /ping 2606:1c80:0:10::253 count=3   ;; core loopback (via preseem)
#   /ip route check dst=2606:1c80:0:10::101  ;; verona loopback path
