Configuring BGP Anycast Routing Nodes (5078)
Executive Summary
Anycast routing via BGP enables multiple geographically dispersed nodes to share a single IP prefix, providing automatic client proximity routing and DDoS resilience. This guide details the production-grade configuration for Votion Cloud's AS5078 anycast fabric, spanning 32 PoPs across 6 continents. We cover kernel-level TCP/IP stack hardening, BGP session templates, community-based traffic engineering, health-check driven withdrawal, and CI/CD integration for zero-downtime rollouts.
Key Outcomes
- Sub-50ms failover convergence across 32 PoPs
- Zero packet loss during rolling upgrades
- Automated capacity-aware traffic steering via BGP communities
- Full observability with eBPF-based flow telemetry
Architecture Overview
The anycast fabric consists of three logical layers:
- Edge Nodes: Bare-metal servers (Dell R750, dual Xeon 8380, 256GB RAM, dual 100GbE NICs) running Ubuntu 22.04 LTS with custom kernel 6.5.x.
- Route Reflectors: Dedicated Juniper MX204 clusters per region running JunOS 22.4R3, providing iBGP mesh reduction and policy enforcement.
- Control Plane: Go-based controller (
anycastd) that consumes health checks, computes optimal community sets, and pushes BGP updates via gRPC to FRR 9.1 on edge nodes.
Each edge node announces the anycast prefix (203.0.113.0/24 IPv4, 2001:db8::/48 IPv6) with a unique site community (e.g., 5078:1001 for FRA-1) and a capacity community (e.g., 5078:2000 for 100Gbps capacity). Upstream transit providers receive these communities and apply local-pref adjustments to steer traffic toward healthier, higher-capacity sites.
eBPF/XDP kernel filter evaluates TCP/UDP frames directly on server NIC.
Kernel & Network Stack Hardening
Before BGP configuration, the Linux network stack must be tuned for high-connection-rate anycast workloads. The following sysctl parameters are applied via /etc/sysctl.d/99-anycast.conf and loaded at boot:
# TCP stack for high connection rates
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 250000
net.ipv4.tcp_max_syn_backlog = 250000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
# Buffer scaling for 100GbE
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
# BGP/ECMP optimizations
net.ipv4.fib_multipath_hash_policy = 1
net.ipv6.fib_multipath_hash_policy = 1
net.ipv4.route.gc_thresh = 4096
net.ipv6.route.gc_thresh = 4096
# Disable ICMP redirects (security)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
Additionally, enable XDP on NICs for early DDoS drop and eBPF flow accounting. The anycastd agent loads a custom XDP program that rate-limits SYN floods per source /24 and exports flow metrics to Prometheus via a Unix socket.
Health-Check Driven Withdrawal
Static anycast announcements are dangerous; a failed application must withdraw its prefix immediately. anycastd runs a gRPC health-check loop against the local service (HTTP /healthz, TCP connect, or custom gRPC). On failure, it dynamically modifies the FRR configuration via vtysh -c to apply a withdraw community (5078:666) that triggers upstream providers to drop the route via pre-configured inbound policy.
Withdrawal sequence (target < 2s):
- Health check fails 3 consecutive times (1s interval)
anycastdsendsvtysh -c "configure terminal" -c "route-map ANYCAST_V4_OUT permit 10" -c "set community 5078:666 additive" -c "end" -c "write memory"- FRR re-announces prefix with withdraw community
- Transit providers' inbound policy matches
5078:666and sets local-pref 0 / deny - Traffic shifts to healthy PoPs within BGP convergence window
Recovery is symmetric: when health checks pass, the withdraw community is removed and normal communities restored.
CI/CD Pipeline for Zero-Downtime Rollouts
All BGP configuration changes flow through a GitOps pipeline. The anycast-config repository contains per-site FRR snippets generated from a Helm chart. Changes are validated by:
- Syntax Check:
frr-ctl --dry-runin CI container - Topology Simulation: Batfish model verifies no blackholes, loops, or policy regressions
- Canary Deploy: Push to 1 PoP per region, monitor telemetry for 10min
- Progressive Rollout: 25% → 50% → 100% with automated rollback on error rate > 0.1%
Rollback is a single git revert; the pipeline re-applies previous config within 90s globally.
Observability & Telemetry
Each node exports:
- BGP RIB: Full Adj-RIB-In/Out via gNMI to Prometheus (scraped every 15s)
- Flow Metrics: eBPF-based per-flow counters (src/dst IP, port, proto, bytes, packets) aggregated to 1s windows
- Health State:
anycastdexposesanycast_node_healthy{site="fra-1"}gauge - Kernel Counters:
netstat -sparsed for TCP retransmits, SYN queue overflows
Grafana dashboards provide real-time anycast health map, convergence timelines, and capacity utilization heatmaps. Alerting rules trigger PagerDuty on:
- Any node unhealthy > 30s
- BGP session flap > 5/min
- Prefix withdrawal detected on > 2 transit sessions
- ECMP imbalance > 20% across paths