## Hardware / Software
- RouterBOARD RB450Gx4, RouterOS **7.23.2 (stable)**, arm architecture
- Factory firmware 7.16.2, current/upgraded firmware 7.23.2
## Background / Existing Setup
We run a dual-WAN setup with ECMP PCC load-balancing that has been working reliably for a long time:
```
/ip route
add dst-address=0.0.0.0/0 gateway=100.64.0.1%ether1-ISP routing-table=*400 check-gateway=arp distance=1 comment="PCC route ether1"
add dst-address=0.0.0.0/0 gateway=100.64.0.1%ether2-ISP routing-table=*401 check-gateway=arp distance=1 comment="PCC route ether2"
```
(Existing PCC mangle rules mapping to `*400`/`*401` are omitted — standard per-connection-classifier pattern, and confirmed working.)
`ether1-ISP` and `ether2-ISP` are both DHCP clients sharing the **same gateway** `100.64.0.1/10` (CGNAT shared address space). Each interface receives a different public/CGNAT IP (e.g. `100.83.12.163` vs `100.108.62.245`).
## Goal
Force traffic originating from a specific set of LAN subnets (bridged on `ether3`, sub-VLANs `10.10.10.0/24`, `10.10.20.0/24`, `10.10.70.0/24`, and a pool named "ultimate" on `10.10.50.0/24`) to **always** egress via `ether1-ISP` — bypassing the normal ECMP 50/50 split — with automatic fallback to `ether2-ISP` if `ether1-ISP` becomes unreachable.
## Configuration Attempted (latest iteration, with local-traffic exclusion)
```
/routing/table
add name=to-ether1-dedicated fib
/ip route
add dst-address=0.0.0.0/0 gateway=100.64.0.1%ether1-ISP routing-table=to-ether1-dedicated check-gateway=arp distance=1 comment="Dedicated primary: ether1"
add dst-address=0.0.0.0/0 gateway=100.64.0.1%ether2-ISP routing-table=to-ether1-dedicated check-gateway=arp distance=2 comment="Dedicated fallback: ether2"
/routing/rule
add routing-mark=to-ether1-dedicated action=lookup-only-in-table table=to-ether1-dedicated
/ip firewall mangle
add chain=prerouting action=mark-connection src-address=10.10.10.0/24 dst-address-type=!local dst-address=!10.0.0.0/8 connection-state=new connection-mark=no-mark new-connection-mark=to-ether1-conn passthrough=yes
add chain=prerouting action=mark-connection src-address=10.10.20.0/24 dst-address-type=!local dst-address=!10.0.0.0/8 connection-state=new connection-mark=no-mark new-connection-mark=to-ether1-conn passthrough=yes
add chain=prerouting action=mark-connection src-address=10.10.70.0/24 dst-address-type=!local dst-address=!10.0.0.0/8 connection-state=new connection-mark=no-mark new-connection-mark=to-ether1-conn passthrough=yes
add chain=prerouting action=mark-connection src-address=10.10.50.0/24 dst-address-type=!local dst-address=!10.0.0.0/8 connection-state=new connection-mark=no-mark new-connection-mark=to-ether1-conn passthrough=yes
add chain=prerouting action=mark-routing connection-mark=to-ether1-conn new-routing-mark=to-ether1-dedicated passthrough=no
```
We deliberately excluded local and inter-LAN traffic (`dst-address-type=!local`, `dst-address=!10.0.0.0/8`) in the `mark-connection` rules, following the guidance in MikroTik's own documentation on the "local traffic gets blackholed" pitfall: Moving from ROSv6 to v7 with examples - RouterOS - MikroTik Documentation
## Observed Behavior
1. **Mangle counters increment normally.** Both the `mark-connection` and `mark-routing` rules show hit counts climbing into the hundreds/thousands, confirming the traffic is being matched and marked as expected.
2. **Router-originated traffic to the local LAN gateway is unaffected.** Pinging from the router itself to its own `ether3` address (`10.10.70.1`) stays healthy (~350 µs RTT) — this rules out the classic "local subnet traffic gets sent into the dedicated table and blackholed" failure mode, since we already excluded local/LAN destinations.
3. **However, real clients behind the marked subnet lose internet access entirely.** A laptop on `10.10.70.0/24` reports "no internet at all" the moment the second mangle rule (`mark-routing`) is enabled. Removing that single rule (or the entire dedicated mangle set) immediately restores internet access for that client — nothing else changes.
4. **Routes inside the custom table (`to-ether1-dedicated`) show `inactive=true` persistently**, even though `check-gateway=arp` for `100.64.0.1` on `ether1-ISP` is confirmed `reachable` in the ARP table (`/ip arp print` shows `status=reachable complete=true`). For comparison, the pre-existing PCC routes (`*400`/`*401` above, proven to work for years) **also** show `inactive=true` in this RouterOS version — so we are not confident this flag is a reliable indicator of failure here.
5. **We also tried a recursive-route variant**, probing a host route to `8.8.8.8/32` with `check-gateway=ping` (since the gateway `100.64.0.1` itself does not answer ICMP echo, despite the link/ARP being healthy). The recursive default route never resolves and stays `active=None`.
## Questions
1. Is there a known interaction between a custom routing-table + `mark-routing` and a subnet that **also has its own local DHCP server** on the same router (the `ether3` bridge runs `/ip dhcp-server` for both `10.10.10.0/24` and `10.10.70.0/24`)? Does DHCP lease-renewal traffic (broadcast/unicast to the local gateway) need an exclusion beyond `dst-address-type=!local`?
2. Is `inactive=true` on a route inside a custom table with `check-gateway=arp` actually meaningful/diagnostic in 7.23.2, or is it cosmetic noise unrelated to whether the gateway is properly resolved for that table? Why would it also show `inactive=true` on the main-table PCC routes that are demonstrably working?
3. Is there a more reliable pattern in RouterOS 7.23.2 for "force subnet X to always egress a specific interface, with automatic failover" on a topology like this (shared-gateway dual WAN, per-subnet policy routing, local DHCP on the affected bridge)?
Any pointers — including "you're doing X fundamentally wrong" — would be very much appreciated. Happy to share full `/export` output for the relevant sections if useful.
Thanks in advance.