154 lines
5.4 KiB
YAML
154 lines
5.4 KiB
YAML
---
|
|
# Configures BIRD2 on the D-Link as an iBGP peer of the MikroTik CRS418.
|
|
#
|
|
# Route exchange:
|
|
# D-Link → CRS: announces 0.0.0.0/0 and 2000::/3 when wwan0 is up.
|
|
# CRS installs these at BGP distance 200 (below the GPON
|
|
# static default at distance 1 — activates only on GPON failure).
|
|
#
|
|
# CRS → D-Link: announces connected routes (VLAN subnets), static routes
|
|
# (Tailscale, GPON default), and reflects k8s BGP routes.
|
|
# BIRD2 installs all of these into the kernel at metric 10.
|
|
#
|
|
# D-Link's own routing:
|
|
# - Kernel metric 10: BGP-learned routes from CRS (preferred)
|
|
# - Kernel metric 100: wwan QMI-assigned routes (fallback)
|
|
# No static default gateway on uplink — the default comes from BGP.
|
|
# When GPON fails, CRS withdraws the BGP default; D-Link falls back to wwan.
|
|
|
|
- name: Write BIRD2 configuration
|
|
community.openwrt.copy:
|
|
dest: /etc/bird.conf
|
|
mode: '0640'
|
|
owner: root
|
|
group: root
|
|
content: |
|
|
# BIRD2 — LTE failover BGP peer for MikroTik CRS418
|
|
# iBGP session, AS 65000, peer: 192.168.6.1 (CRS vlan6)
|
|
|
|
router id 192.168.6.2;
|
|
|
|
protocol device {
|
|
# Tracks interface up/down state via netlink.
|
|
# scan time is a periodic reconciliation fallback; real events are
|
|
# netlink-driven and processed immediately.
|
|
scan time 5;
|
|
}
|
|
|
|
# Announce directly connected prefixes into BIRD2's RIB so that
|
|
# next-hop resolution works for BGP routes received from CRS.
|
|
# Without this, 192.168.6.1 (CRS uplink) is unresolvable and all
|
|
# IPv4 BGP routes appear unreachable. Same for IPv6 uplink prefix.
|
|
protocol direct {
|
|
ipv4;
|
|
ipv6;
|
|
interface "eth0.6";
|
|
}
|
|
|
|
# Install BGP-learned routes from CRS into the kernel at metric 10.
|
|
# This is lower than the wwan QMI default (metric 100), so D-Link
|
|
# prefers the CRS path for its own outbound traffic when GPON is up.
|
|
# import none: BIRD2 does not read the kernel table, preventing
|
|
# wwan kernel routes from leaking into BGP.
|
|
protocol kernel k4 {
|
|
ipv4 {
|
|
import none;
|
|
export filter {
|
|
if proto = "crs" then {
|
|
krt_metric = 10;
|
|
accept;
|
|
}
|
|
reject;
|
|
};
|
|
};
|
|
}
|
|
|
|
protocol kernel k6 {
|
|
ipv6 {
|
|
import none;
|
|
export filter {
|
|
if proto = "crs" then {
|
|
krt_metric = 10;
|
|
accept;
|
|
}
|
|
reject;
|
|
};
|
|
};
|
|
}
|
|
|
|
# LTE default routes — exist only while wwan0 is up.
|
|
# BIRD2's device protocol tracks wwan0 via netlink; when the interface
|
|
# goes down the routes become unreachable and BGP withdraws them.
|
|
# Uses interface-name routing (no explicit gateway IP) which is correct
|
|
# for QMI raw-ip POINTOPOINT NOARP interfaces.
|
|
#
|
|
# Preference 50 is below BGP's default of 100 — these routes are only
|
|
# used by BIRD2 internally as a presence signal for BGP export, NOT for
|
|
# installing into the kernel as our active default route. The kernel
|
|
# already gets the wwan default at metric 100 via netifd/qmi.sh, and
|
|
# we want the BGP-learned default via CRS (kernel metric 10) to be
|
|
# preferred for D-Link's own outbound traffic when GPON is up.
|
|
protocol static lte_default {
|
|
ipv4 {
|
|
preference 50;
|
|
};
|
|
route 0.0.0.0/0 via "wwan0";
|
|
}
|
|
|
|
protocol static lte_default6 {
|
|
ipv6 {
|
|
preference 50;
|
|
};
|
|
route 2000::/3 via "wwan0";
|
|
}
|
|
|
|
protocol bgp crs {
|
|
description "MikroTik CRS418 — LTE failover signalling";
|
|
local 192.168.6.2 as 65000;
|
|
neighbor 192.168.6.1 as 65000;
|
|
hold time 30;
|
|
keepalive time 10;
|
|
|
|
ipv4 {
|
|
# Import all prefixes CRS announces (VLAN subnets, static routes,
|
|
# k8s BGP routes reflected via RR). Installed into kernel via k4.
|
|
import all;
|
|
# Export only the wwan-sourced LTE default route.
|
|
# BGP-learned CRS routes are never re-exported (iBGP split-horizon
|
|
# applies; BIRD2 also does not import CRS routes into its RIB from
|
|
# the kernel, so they cannot appear here).
|
|
export where proto = "lte_default";
|
|
};
|
|
|
|
ipv6 {
|
|
# CRS uses Extended Next Hop (RFC 5549) for IPv6 routes, advertising
|
|
# them with the IPv4 next-hop 192.168.6.1. The Linux kernel cannot
|
|
# install IPv6 routes with IPv4 next-hops. Accept the routes from BGP
|
|
# (we negotiated ENHE via "extended next hop yes") but rewrite the
|
|
# next-hop in the import filter to the CRS's native IPv6 address on
|
|
# vlan6 before they reach the kernel.
|
|
extended next hop yes;
|
|
import filter {
|
|
gw = 2001:470:61a3:600::1;
|
|
accept;
|
|
};
|
|
# Force our own native IPv6 address as the next-hop when advertising
|
|
# to CRS, otherwise BIRD2 also uses ENHE and CRS receives a route
|
|
# with ::ffff:192.168.6.2 which it can't resolve as an IPv6 next-hop.
|
|
export filter {
|
|
if proto = "lte_default6" then {
|
|
bgp_next_hop = 2001:470:61a3:600::2;
|
|
accept;
|
|
}
|
|
reject;
|
|
};
|
|
};
|
|
}
|
|
notify: Reload bird
|
|
|
|
- name: Enable and start BIRD2 service
|
|
community.openwrt.service:
|
|
name: bird
|
|
enabled: true
|
|
state: started
|