4.5 Abnahme bestanden: 0% Ping-Loss auf alle BF-VLANs (vorher 100%), TCP mit echtem Datenfluss ok, FQDN-Smoke beweist cloudflared-Public-Teil unberuehrt. 4.6 Auflage #4 erfuellt: Ist-Stand als intended config nach Nautobot, 65/68 -> Template ergaenzt -> 68/68 keine Drifts. Zentrale Falle dokumentiert: /ip service address=10.40.0.0/16 sperrt das Router-Mgmt aus der Mesh-Range 100.96.0.0/12 aus - Ping geht, SSH/REST/MikroMCP sterben. Fuer branch/ap1/ap2 noch offen. Und: nc -z ueber WARP ist kein Reachability-Beweis, der CF-Proxy terminiert den Handshake. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
292 lines
19 KiB
Django/Jinja
292 lines
19 KiB
Django/Jinja
# Nautobot Golden Config -- intended RouterOS config for {{ obj.name }}
|
|
#
|
|
# FORMAT-REGEL (TP22, 2026-08-13): Zeilen sind im RouterOS-**/export-Format** geschrieben
|
|
# (Space-Form `/ip address add ...`, Attribute ALPHABETISCH), nicht in der Slash-Form der
|
|
# Provisionierungs-Skripte. Golden Config vergleicht Backup (= echter /export) und Intended
|
|
# textuell -- jede Abweichung in Reihenfolge, Quoting oder Pfadform ist ein Falsch-Drift.
|
|
# Referenz-Exporte: routeros/state-backups/*-gc-backup-scrubbed-*.cfg
|
|
#
|
|
# Secrets tragen die Maske "<<REDACTED>>" der ConfigReplace-Backup-Regeln.
|
|
# 🔴 Zeilen mit <<REDACTED>> duerfen NIE per Deploy gepusht werden.
|
|
|
|
/system identity set name={{ obj.name }}
|
|
|
|
{% if obj.name == "crs326-core" %}
|
|
{#- VLAN-Tabelle: Site-Konstante. name = RouterOS-comment, lease/pool je VLAN. -#}
|
|
{%- set vlans = [
|
|
{"id": 10, "name": "MAIN", "pool": "10.40.10.100-10.40.10.200", "lease": "1d"},
|
|
{"id": 20, "name": "INFRA", "pool": "10.40.20.100-10.40.20.200", "lease": "1d"},
|
|
{"id": 30, "name": "IOT", "pool": "10.40.30.100-10.40.30.250", "lease": "1d"},
|
|
{"id": 40, "name": "MEDIA", "pool": "10.40.40.100-10.40.40.200", "lease": "1d"},
|
|
{"id": 50, "name": "UNTRUSTED", "pool": "10.40.50.100-10.40.50.200", "lease": "1d"},
|
|
{"id": 90, "name": "GUEST", "pool": "10.40.90.100-10.40.90.200", "lease": "12h"},
|
|
{"id": 99, "name": "MGMT", "pool": "10.40.99.100-10.40.99.200", "lease": "1d"}
|
|
] %}
|
|
# =====================================================================================
|
|
# crs326-core — PRODUKTIVER L3-Router (seit Cutover 2026-08-08, TP21.1).
|
|
# Die frueheren `disabled=yes`-Staging-Flags sind ENTFERNT: sie stammten aus der
|
|
# Vorbereitung des Cutovers und beschreiben nicht mehr den Sollzustand.
|
|
# =====================================================================================
|
|
|
|
# [0] L2-FABRIC — Bridge-Ports + Bridge-VLAN-Tabelle.
|
|
# Literal-Block, KEINE Ableitung aus DCIM: der As-built traegt bewusste Schiefstaende
|
|
# (ether3 ist untagged-Member von VLAN40, hat aber pvid=1; ether2 haengt zusaetzlich in
|
|
# VLAN1). Wuerde man pvid aus `untagged_vlan` generieren, meldete die Compliance genau
|
|
# diese akzeptierten Altlasten als Dauerdrift. Der Block ist damit das, was Golden Config
|
|
# fuer einen handgebauten L2-Layer leisten soll: Drift-Erkennung gegen den Ist-Zustand.
|
|
# `/interface bridge` selbst ist bewusst NICHT abgedeckt (traegt die geraetespezifische
|
|
# admin-mac -> waere pro Geraet verschieden und ist kein Fleet-Standard).
|
|
/interface bridge port add bridge=bridge comment=defconf frame-types=admit-only-vlan-tagged interface=ether1
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether2 pvid=40
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether3
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether4 pvid=40
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether5 pvid=40
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether6 pvid=40
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether7
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether8
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether9
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether10
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether11 pvid=10
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether12
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether13
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether14 pvid=30
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether15
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether16 pvid=100
|
|
{% for n in range(17, 25) %}
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether{{ n }}
|
|
{% endfor %}
|
|
/interface bridge port add bridge=bridge comment=defconf interface=sfp-sfpplus1
|
|
/interface bridge port add bridge=bridge comment=defconf interface=sfp-sfpplus2
|
|
# ether4 = Wohnzimmer-Sideboard: 2026-08-13 von Trunk auf untagged VLAN40 gezogen (TP21.1/4).
|
|
/interface bridge vlan add bridge=bridge untagged=ether1,ether2 vlan-ids=1
|
|
/interface bridge vlan add bridge=bridge tagged=ether1,ether8,ether15 vlan-ids=10
|
|
/interface bridge vlan add bridge=bridge tagged=ether8,ether13,ether15 vlan-ids=20
|
|
/interface bridge vlan add bridge=bridge tagged=ether1,ether8,ether15 untagged=ether14 vlan-ids=30
|
|
/interface bridge vlan add bridge=bridge tagged=ether1,ether8,ether15 untagged=ether2,ether3,ether4,ether5 vlan-ids=40
|
|
/interface bridge vlan add bridge=bridge tagged=ether1,ether8,ether15 vlan-ids=50
|
|
/interface bridge vlan add bridge=bridge tagged=ether1,ether8,ether15 vlan-ids=90
|
|
/interface bridge vlan add bridge=bridge tagged=ether8,ether15,bridge vlan-ids=99
|
|
/interface bridge vlan add bridge=bridge tagged=ether1 untagged=ether16 vlan-ids=100
|
|
|
|
# [1] INTERFACE-LISTS
|
|
/interface list add comment=TP15 name=WAN
|
|
/interface list add comment=TP15 name=LAN
|
|
/interface list member add interface=vlan100 list=WAN
|
|
{% for v in vlans %}
|
|
/interface list member add interface=vlan{{ v.id }} list=LAN
|
|
{% endfor %}
|
|
|
|
# [2] VLAN-SVIs auf der Bridge (vlan99 traegt bewusst keinen comment)
|
|
{% for v in vlans %}
|
|
/interface vlan add {% if v.id != 99 %}comment={{ v.name }} {% endif %}interface=bridge name=vlan{{ v.id }} vlan-id={{ v.id }}
|
|
{% endfor %}
|
|
/interface vlan add comment=WAN interface=bridge name=vlan100 vlan-id=100
|
|
|
|
# [3] GW-IPs je VLAN — datengetrieben aus Nautobot (IP am SVI-Interface gebunden).
|
|
# comment = Interface-Description; network wird aus der Host-IP abgeleitet.
|
|
{% for iface in obj.interfaces.all() %}
|
|
{% if iface.name.startswith("vlan") %}
|
|
{% for ip in iface.ip_addresses.all() %}
|
|
/ip address add address={{ ip.address }} comment="{{ iface.description }}" interface={{ iface.name }} network={{ ip.host.split(".")[:3] | join(".") }}.0
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
# [4] WAN — DHCP-Client auf vlan100 (Liwest/Arris)
|
|
/ip dhcp-client add comment="WAN Arris DHCP (Liwest) via vlan100" interface=vlan100 use-peer-dns=no use-peer-ntp=no
|
|
|
|
# [5] DHCP-Server je VLAN
|
|
{% for v in vlans %}
|
|
/ip pool add name=pool-v{{ v.id }} ranges={{ v.pool }}
|
|
{% endfor %}
|
|
{% for v in vlans %}
|
|
/ip dhcp-server add address-pool=pool-v{{ v.id }} comment={{ v.name }} interface=vlan{{ v.id }} lease-time={{ v.lease }} name=dhcp-v{{ v.id }}
|
|
{% endfor %}
|
|
{% for v in vlans %}
|
|
/ip dhcp-server network add address=10.40.{{ v.id }}.0/24 dns-server=10.40.{{ v.id }}.1 domain=bf.lan gateway=10.40.{{ v.id }}.1
|
|
{% endfor %}
|
|
/ip dhcp-server option add code=6 name="dns 1.1.1.1" value=0x01010101
|
|
|
|
# [6] DNS — Upstream aktuell PLAIN 1.1.1.1. DoH-Cloudflare-Gateway ist offener TODO
|
|
# (core hat kein CA-Bundle -> verify-doh-cert nicht moeglich), s. TP21.1.
|
|
/ip dns set allow-remote-requests=yes mdns-repeat-ifaces=vlan10,vlan20,vlan40,vlan30,vlan90 servers=1.1.1.1
|
|
|
|
# Kanonischer Mgmt-Nummernplan (User-Bestaetigung 2026-08-13, verbindlich):
|
|
# core .99.1 | branch .99.2 | ap1 .99.11 | ap2 .99.12
|
|
/ip dns static add address=10.40.99.1 comment="core = GW/Router" name=router.lan type=A
|
|
/ip dns static add address=10.40.99.1 comment="crs326-core (L3)" name=core.bf.lan type=A
|
|
/ip dns static add address=10.40.99.2 comment=crs326-branch name=branch.bf.lan type=A
|
|
/ip dns static add address=10.40.99.11 comment="ap1 = reiner AP" name=ap1.bf.lan type=A
|
|
/ip dns static add address=10.40.99.12 comment="ap2 = reiner AP" name=ap2.bf.lan type=A
|
|
/ip dns static add address=10.40.20.167 name=macmini.bf.lan type=A
|
|
/ip dns static add address=10.40.20.100 name=pve.bf.lan type=A
|
|
/ip dns static add address=10.40.20.173 name=pve-mcp.bf.lan type=A
|
|
/ip dns static add address=10.40.20.10 name=nas.bf.lan type=A
|
|
/ip dns static add address=10.40.20.126 name=docker.bf.lan type=A
|
|
/ip dns static add address=10.40.20.20 name=platform-pg.bf.lan type=A
|
|
|
|
# [7] NAT
|
|
/ip firewall nat add action=accept chain=srcnat comment="TP4: no-NAT inter-VLAN (LAN-internal, before masquerade)" dst-address=10.40.0.0/16
|
|
/ip firewall nat add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN
|
|
|
|
# [8] ROUTEN zu den WG-Spokes (Default-Route kommt dynamisch vom WAN-DHCP-Client)
|
|
/ip route add comment="TP10: FM spoke -> wg-hub" dst-address=10.101.0.0/24 gateway=wg-hub
|
|
/ip route add comment="TP10: DW spoke -> wg-hub" dst-address=10.95.10.0/24 gateway=wg-hub
|
|
|
|
# [9] WG-HUB (TP10 Multi-Site). Der echte Privkey liegt in routeros/ap1-wg-hub.privkey.
|
|
/interface wireguard add comment="TP10 Multi-Site VPN Hub (FM/DW spokes)" listen-port=51821 mtu=1412 name=wg-hub private-key="<<REDACTED>>"
|
|
/interface wireguard peers add allowed-address=10.101.0.0/24 comment=fm endpoint-address=abxhutfgsid9snmy.myfritz.net endpoint-port=52476 interface=wg-hub name=fm public-key="dzRY0lnnUygijChWe5wXZmXPeNcbdALpqBptA3fyiVE="
|
|
/interface wireguard peers add allowed-address=10.95.10.0/24 comment=dw interface=wg-hub name=dw public-key="FqYZLztQ/qME5VDie5QLGH++5299WJiE1dPpQnPbzUw="
|
|
|
|
# [10] CF-MESH (TP16.1) — privater Zugang unterwegs via natives WireGuard zum CF-PoP.
|
|
# Ersetzt den cloudflared-QUIC-Proxy fuer 10.40.0.0/16 (die oeffentlichen FQDNs bleiben
|
|
# auf dem 3-Tunnel-HA aus TP16). Privkey kommt von CLOUDFLARE, nicht vom Geraet — er
|
|
# steht in mcp/cloudflare/.env (CF_MESH_PRIVKEY, gitignored) und wurde einmalig per SSH
|
|
# eingespielt; hier nur die Backup-Maske, wie bei wg-hub.
|
|
# MTU 1420 aus dem animmouse-Guide. Vergleichswert auf demselben Geraet: wg-hub = 1412.
|
|
# Bei Path-MTU-Symptomen (TCP baut auf, grosse Transfers haengen) zuerst dorthin angleichen.
|
|
# Peer wurde von RouterOS zunaechst "peer5" auto-benannt und auf "cf-pop" umbenannt.
|
|
# ⚠️ MikroMCPs manage_wireguard_peer kennt weder persistent-keepalive noch einen Namen,
|
|
# und es schreibt endpoint="IP:Port" komplett in endpoint-address (endpoint-port bleibt 0
|
|
# -> KEIN Handshake). Nach jedem Peer-Add per `print detail` gegenlesen.
|
|
/interface wireguard add comment="TP16.1 Cloudflare Mesh" listen-port=13279 mtu=1420 name=cf-mesh private-key="<<REDACTED>>"
|
|
/interface wireguard peers add allowed-address=0.0.0.0/0 comment="TP16.1 CF-PoP" endpoint-address=162.159.193.2 endpoint-port=2408 interface=cf-mesh name=cf-pop persistent-keepalive=25s public-key="bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo="
|
|
/ip address add address=100.96.0.6 comment="TP16.1 Mesh-Overlay" interface=cf-mesh network=100.96.0.6
|
|
/ip route add comment="TP16.1 Mesh" disabled=no distance=1 dst-address=100.96.0.0/12 gateway=cf-mesh
|
|
{% elif obj.role.name == "Switch" %}
|
|
# =====================================================================================
|
|
# L2-Switch (crs326-branch) — Sollzustand des Mgmt-Layers.
|
|
# Bewusst NICHT emittiert: die TEMP-Bring-up-Objekte (vlan10 "TEMP Mgmt VLAN10" +
|
|
# 10.40.10.2). Die tauchen dadurch als Compliance-`extra` auf — genau richtig, denn sie
|
|
# sind Altlast aus dem Bring-up und gehoeren entfernt (VLAN1/VLAN10-Interim, TP19).
|
|
# =====================================================================================
|
|
/interface vlan add comment=MGMT interface=bridge name=vlan99 vlan-id=99
|
|
/ip address add address={{ obj.primary_ip4.address }} comment=TP21-mgmt-target interface=vlan99 network={{ obj.primary_ip4.host.split(".")[:3] | join(".") }}.0
|
|
/ip dns set servers=10.40.99.1
|
|
/ip route add comment=TP21-default dst-address=0.0.0.0/0 gateway=10.40.99.1
|
|
|
|
# L2-FABRIC — wie beim Core ein Literal-Block (Begruendung dort).
|
|
# ether9-23 tragen pvid=20 OHNE VLAN-Membership (Bootstrap-Rev4-Rest, funktionslos) —
|
|
# bewusst so abgebildet, damit eine spaetere Bereinigung als Drift sichtbar wird.
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether1
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether2
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether3 pvid=10
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether4 pvid=10
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether5 pvid=40
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether6 pvid=40
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether7 pvid=20
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether8
|
|
{% for n in range(9, 24) %}
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether{{ n }} pvid=20
|
|
{% endfor %}
|
|
/interface bridge port add bridge=bridge comment=defconf interface=ether24
|
|
/interface bridge port add bridge=bridge comment=defconf disabled=yes interface=sfp-sfpplus1
|
|
/interface bridge port add bridge=bridge comment=defconf disabled=yes interface=sfp-sfpplus2
|
|
/interface bridge vlan add bridge=bridge comment=MAIN tagged=ether1,ether24,bridge untagged=ether3,ether4 vlan-ids=10
|
|
/interface bridge vlan add bridge=bridge comment=INFRA tagged=ether1,ether24,bridge,ether2,ether8 untagged=ether7 vlan-ids=20
|
|
/interface bridge vlan add bridge=bridge comment=IOT tagged=ether1,ether24,bridge vlan-ids=30
|
|
/interface bridge vlan add bridge=bridge comment=MEDIA tagged=ether1,ether24,bridge untagged=ether5,ether6 vlan-ids=40
|
|
/interface bridge vlan add bridge=bridge comment=UNTRUSTED tagged=ether1,ether24,bridge vlan-ids=50
|
|
/interface bridge vlan add bridge=bridge comment=GUEST tagged=ether1,ether24,bridge vlan-ids=90
|
|
/interface bridge vlan add bridge=bridge comment=MGMT tagged=ether1,ether24,bridge vlan-ids=99
|
|
{% elif obj.role.name == "Wireless AP" %}
|
|
{% set ap = obj.get_config_context()["ap"] %}
|
|
{% set mgmt_host = obj.primary_ip4.host %}
|
|
{% set uplink = ap.uplink %}
|
|
# =====================================================================================
|
|
# TP22 — Standalone-AP (kein CAPsMAN). Gerendert aus ConfigContext "ap-common"
|
|
# + Device.local_config_context_data (Kanaele) + DCIM (Name, primary_ip4).
|
|
#
|
|
# SCOPE: nur die COMPLIANCE-VERWALTETEN Sektionen, bewusst NICHT die ganze Config.
|
|
# Golden Config vergleicht per ComplianceRule.match_config sektionsweise -> defconf-
|
|
# Boilerplate (ipv4/ipv6-Firewall, /disk, /tool mac-server) und die VAP-Zeilen
|
|
# (/interface wifi add ... mac-address=...) bleiben draussen: deren MACs sind
|
|
# geraetevergeben und in Nautobot nicht modelliert.
|
|
#
|
|
# 🔴 NIE als Ganzes auf ein laufendes Geraet pushen: die Provisionierung setzt
|
|
# zwischenzeitlich vlan-filtering=no, was den vlan99-Mgmt-Pfad abreisst -> der Rest
|
|
# der Zeilen kaeme ueber dieselbe SSH-Session nie an. Voll-Reprovisionierung
|
|
# ausschliesslich per Datei-Upload + /import (siehe routeros/.secrets/ap*-prov-base.rsc).
|
|
#
|
|
# Attributreihenfolge = alphabetisch, exakt wie RouterOS /export sie schreibt.
|
|
# Referenz: routeros/state-backups/ap1-gc-backup-scrubbed-20260813.cfg
|
|
# =====================================================================================
|
|
|
|
# [1] CHANNELS — Frequenz aus der Kanalnummer gerechnet (eine Quelle der Wahrheit)
|
|
{% for r in ap.radios %}
|
|
{% set ch = ap.channels[r.key] %}
|
|
{% set freq = (5000 + 5 * ch) if r.key == "5g" else (2407 + 5 * ch) %}
|
|
/interface wifi channel add band={{ r.band }} frequency={{ freq }} name=ch-{{ r.key }} width={{ r.width }}
|
|
{% endfor %}
|
|
|
|
# [2] DATAPATH — je Zone ein VLAN-Tag. OHNE datapath egressiert die SSID ungetaggt
|
|
# in VLAN1 (das war das TP3.1-Leck) -> jede Zone MUSS hier auftauchen.
|
|
{% for z in ap.zones %}
|
|
/interface wifi datapath add bridge={{ ap.bridge }} name=dp-{{ z.name }} vlan-id={{ z.vlan }}
|
|
{% endfor %}
|
|
|
|
# [3] SECURITY — Passphrasen tragen die Backup-Maske aus TP22 Schritt 0.
|
|
# ft-over-ds schreibt RouterOS nur, wenn ft=yes.
|
|
{% for z in ap.zones %}
|
|
/interface wifi security add authentication-types={{ z.auth }} ft={{ z.ft }}{% if z.ft == "yes" %} ft-over-ds={{ z.ft_over_ds }}{% endif %} name=sec-{{ z.name }} passphrase="<<REDACTED>>"
|
|
{% endfor %}
|
|
|
|
# [3b] STEERING — 802.11k (rrm: Neighbor Reports) + 802.11v (wnm: BSS Transition).
|
|
# OHNE das klebt der Client am sterbenden AP, bis die Verbindung abreisst; 802.11r/FT
|
|
# macht die Uebergabe nur SCHNELL, es loest sie nicht aus. Genau das fehlte nach dem
|
|
# TP3-Rebuild auf beiden APs und hat Videocalls beim Durchgehen abgerissen (TP3.3).
|
|
# `neighbor-group` ist site-weit identisch -- nur dann gelten ap1/ap2 als Nachbarn.
|
|
# Konstante statt ConfigContext: es gibt genau EINE Roaming-Domain pro Standort.
|
|
{% set steering = {"name": "st-main", "neighbor_group": "bf-main"} %}
|
|
/interface wifi steering add name={{ steering.name }} neighbor-group={{ steering.neighbor_group }} rrm=yes wnm=yes
|
|
|
|
# [4] CONFIGURATION — main sitzt auf den Master-Radios und bringt den Channel mit
|
|
# (je Band eine configuration); alle anderen Zonen sind Slave-VAPs ohne channel=.
|
|
# steering= haengt nur an den Master-Zonen (RouterOS exportiert es nach ssid=).
|
|
{% for z in ap.zones %}
|
|
{% if z.master %}
|
|
{% for r in ap.radios %}
|
|
{% if r.key in z.bands %}
|
|
/interface wifi configuration add channel=ch-{{ r.key }} country={{ ap.country }} datapath=dp-{{ z.name }} mode=ap name=cfg-{{ z.name }}-{{ r.key }} security=sec-{{ z.name }} ssid={{ z.ssid }} steering={{ steering.name }}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% else %}
|
|
/interface wifi configuration add country={{ ap.country }} datapath=dp-{{ z.name }} mode=ap name=cfg-{{ z.name }} security=sec-{{ z.name }} ssid={{ z.ssid }}
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
# [4b] BRIDGE-PORTS — ether2 fehlt bewusst: seit der Uplink-Umstellung auf ether1 (PoE)
|
|
# ist er KEIN Bridge-Port mehr. ether1 traegt kein comment=defconf (beim Rebuild
|
|
# neu angelegt), die uebrigen schon — deshalb hier nicht ueber einen Kamm geschoren.
|
|
/interface bridge port add bridge={{ ap.bridge }} comment=defconf interface=ether3
|
|
/interface bridge port add bridge={{ ap.bridge }} comment=defconf interface=ether4
|
|
/interface bridge port add bridge={{ ap.bridge }} comment=defconf interface=ether5
|
|
{% for r in ap.radios %}
|
|
/interface bridge port add bridge={{ ap.bridge }} comment=defconf interface={{ r.iface }}
|
|
{% endfor %}
|
|
/interface bridge port add bridge={{ ap.bridge }} interface={{ uplink }}
|
|
|
|
# [5] BRIDGE-VLAN — Nur Master-Radios sind Bridge-Ports (Slave-VAPs forwarden darueber),
|
|
# deshalb muessen wifi1/wifi2 tagged-Member je Client-VLAN sein. Die frueheren
|
|
# "Ausnahmen" fallen hier aus den Daten heraus: IOT hat bands=["2g"] -> nur wifi2.
|
|
/interface bridge vlan add bridge={{ ap.bridge }} untagged={{ ap.bridge }},{{ uplink }} vlan-ids={{ ap.native_vlan }}
|
|
{% for z in ap.zones %}
|
|
{% set members = [uplink] + (ap.radios | selectattr("key", "in", z.bands) | map(attribute="iface") | list) %}
|
|
/interface bridge vlan add bridge={{ ap.bridge }} tagged={{ members | join(",") }} vlan-ids={{ z.vlan }}
|
|
{% endfor %}
|
|
# MGMT liegt auf der Bridge, NICHT auf den Radios - sonst waere Management over-the-air.
|
|
/interface bridge vlan add bridge={{ ap.bridge }} tagged={{ uplink }},{{ ap.bridge }} vlan-ids={{ ap.mgmt.vlan }}
|
|
|
|
# [6] MGMT-LAYER
|
|
# interface-list + dns hier, damit die platform-weiten ComplianceFeatures
|
|
# (gelten pro Platform, nicht pro Rolle) auf APs nicht ins Leere laufen.
|
|
/interface list add comment=defconf name=WAN
|
|
/interface list add comment=defconf name=LAN
|
|
/interface list member add comment=defconf interface={{ ap.bridge }} list=LAN
|
|
/interface list member add interface=vlan{{ ap.mgmt.vlan }} list=LAN
|
|
/ip dns set allow-remote-requests=yes servers={{ ap.mgmt.gateway }}
|
|
/interface vlan add interface={{ ap.bridge }} name=vlan{{ ap.mgmt.vlan }} vlan-id={{ ap.mgmt.vlan }}
|
|
/ip address add address={{ obj.primary_ip4.address }} interface=vlan{{ ap.mgmt.vlan }} network={{ mgmt_host.split(".")[:3] | join(".") }}.0
|
|
/ip route add comment="mgmt default via core" dst-address=0.0.0.0/0 gateway={{ ap.mgmt.gateway }}
|
|
{% endif %}
|