Build log · MikroTik · BGP + BFD failover · CHR relay

MikroTik CHR BFD failover on RouterOS

Bind BFD to the existing MikroTik/CHR BGP session over WireGuard so the IPv6 default route withdraws quickly when the relay path dies.

Overview

This is the MikroTik CHR variant of the BGP+BFD failover companion for the VPS path. It assumes the relay VPS is already running RouterOS CHR with WireGuard wg-vps and an eBGP session to the home router.

BFD does not replace BGP. It gives the existing BGP session a fast liveness signal, so the home router withdraws the learned IPv6 default route when the WireGuard path is dead instead of waiting for the BGP hold timer.

With RouterOS on both ends, the implementation is symmetric: add a BFD configuration for the WireGuard interface on each router, enable BFD on each BGP connection, and permit BFD control packets on the tunnel.

Design decisions

Bind BFD to the existing CHR BGP session. The CHR relay already originates ::/0 to the home router, and the home router already advertises the routed /48 back. BFD should monitor that same eBGP session; it should not introduce another routing path.

Permit BFD explicitly on both routers. RouterOS BFD uses UDP/3784 and UDP/3785. Add tunnel-scoped input rules on both ends so a later input-drop policy cannot leave BGP established while BFD stays down.

Keep Happy Eyeballs behavior intentional. If BFD withdraws the CHR-learned IPv6 default route and no other IPv6 default is active, clients fail IPv6 quickly and move to IPv4. Do not add another IPv6 default route unless you intentionally want a second IPv6 uplink to catch the failure.

1. Conventions and placeholders

Use the same values from the CHR relay variant of the VPS post:

PlaceholderMeaning
<LAN_PREFIX>Routed /48, written without trailing ::.
<HOME_AS> / <VPS_AS>Home router and CHR private ASNs.
wg-vpsWireGuard interface on both RouterOS peers.
homeCHR BGP connection name toward home.
chr-vpsHome router BGP connection name to CHR.

The examples use <LAN_PREFIX>:0::1 on CHR and <LAN_PREFIX>:0::2 on the home router.

2. CHR — enable BFD on the home BGP session

Add a BFD configuration for the CHR WireGuard interface, enable BFD on the existing BGP connection, and allow BFD from the tunnel.

CHR — BFD on the home BGP connection

bash

1/routing/bfd/configuration/add interfaces=wg-vps \ 2 min-rx=200ms min-tx=200ms multiplier=3 \ 3 comment="Home BFD" 4 5/routing/bgp/connection/set [find name=home] use-bfd=yes 6 7/ipv6/firewall/filter/add chain=input action=accept protocol=udp \ 8 in-interface=wg-vps dst-port=3784,3785 comment="BFD from home"

If the CHR input policy has a final drop rule, move the BFD rule above it. For the minimal relay firewall in the CHR VPS post, placing it near the BGP input accept keeps the control-plane surface readable.

3. Home router — enable BFD on the CHR BGP session

Do the matching RouterOS change on the home router.

Home router — BFD on the CHR BGP connection

bash

1/routing/bfd/configuration/add interfaces=wg-vps \ 2 min-rx=200ms min-tx=200ms multiplier=3 \ 3 comment="CHR VPS BFD" 4 5/routing/bgp/connection/set [find name=chr-vps] use-bfd=yes 6 7/ipv6/firewall/filter/add chain=input action=accept protocol=udp \ 8 in-interface=wg-vps dst-port=3784,3785 comment="BFD from chr-vps" 9 10:local bfdRule [/ipv6/firewall/filter/find where comment="BFD from chr-vps"] 11:local dropRule [/ipv6/firewall/filter/find where chain=input and comment="defconf: drop everything else not coming from LAN"] 12/ipv6/firewall/filter/move $bfdRule destination=$dropRule

If a BFD configuration for wg-vps already exists, edit that entry instead of adding a duplicate. If the firewall rule already exists, enable or update it instead of adding a second copy.

4. Verification

Both RouterOS peers should show BFD up, BGP established, and the learned ::/0 installed on the home router.

CHR — BFD, BGP, and return route

bash

1/routing/bfd/session/print detail 2/routing/bgp/session/print detail 3/ipv6/route/print detail where dst-address="<LAN_PREFIX>::/48"

Home router — BFD, BGP, and default route

bash

1/routing/bfd/session/print detail 2/routing/bgp/session/print detail 3/ipv6/route/print detail where dst-address="::/0" 4/ping 2606:4700:4700::1111 count=3

Healthy RouterOS BFD should show:

text

text

1state=up 2actual-tx-interval=200ms 3required-min-rx=200ms 4remote-min-rx=200ms 5remote-min-tx=200ms 6multiplier=3 7hold-time=600ms

5. Failure test

To prove clients get a fast signal, temporarily block BFD on the CHR side and watch the home router withdraw its IPv6 default route.

CHR — temporary BFD block

bash

1/ipv6/firewall/filter/add chain=input action=drop protocol=udp \ 2 in-interface=wg-vps dst-port=3784,3785 comment="TEMP block BFD test"

Home router — watch while testing

bash

1/routing/bfd/session/print detail 2/routing/bgp/session/print detail 3/ipv6/route/print detail where dst-address="::/0"

Remove the temporary block after the test:

CHR — remove temporary BFD block

bash

1/ipv6/firewall/filter/remove [find comment="TEMP block BFD test"]

Expected result:

Failure conditionRouter behavior
BFD downBGP session drops quickly
BGP default withdrawn::/0 via wg-vps disappears
No IPv6 default leftClients fail IPv6 quickly and try IPv4
BFD restoredBGP re-establishes and ::/0 returns via wg-vps

References

Share

Comments

Comments are powered by GitHub Discussions and require a free GitHub account to post.