Set up BIRD 2.15 BGP daemon with advanced routing policies, route filtering, and automated network management. Configure BGP peering, implement complex routing decisions, and set up route aggregation for production networks.
Prerequisites
- Root or sudo access
- Basic BGP knowledge
- Network interface with public IP
- AS number assignment
What this solves
BIRD (Berkeley Internet Routing Daemon) provides advanced BGP routing capabilities for networks requiring sophisticated routing policies and automation. This tutorial covers BIRD 2.15 installation, BGP neighbor configuration, route filtering, and policy implementation for production network environments.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions.
sudo apt update && sudo apt upgrade -y
Install BIRD routing daemon
Install BIRD 2.x which provides unified IPv4 and IPv6 routing support with advanced BGP features.
sudo apt install -y bird2 bird2-doc
Enable IP forwarding
Enable IP forwarding to allow the system to route traffic between networks.
echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Create BIRD configuration directory structure
Set up organized configuration directories for better management of routing policies and filters.
sudo mkdir -p /etc/bird/filters
sudo mkdir -p /etc/bird/policies
sudo mkdir -p /etc/bird/functions
sudo chown -R bird:bird /etc/bird
sudo chmod 755 /etc/bird /etc/bird/filters /etc/bird/policies /etc/bird/functions
Configure main BIRD configuration
Create the main BIRD configuration file with router ID, logging, and basic protocol setup.
# BIRD 2.15 Configuration
Router ID - use your primary interface IP
router id 203.0.113.10;
Logging configuration
log syslog all;
log "/var/log/bird.log" { debug, trace, info, remote, warning, error, auth, fatal, bug };
Include additional configuration files
include "/etc/bird/filters/*.conf";
include "/etc/bird/policies/*.conf";
include "/etc/bird/functions/*.conf";
Enable ECMP (Equal Cost Multi-Path) routing
protocol kernel kernel4 {
ipv4 {
import none;
export filter {
if source = RTS_BGP then {
accept;
}
reject;
};
};
merge paths yes;
learn yes;
}
protocol kernel kernel6 {
ipv6 {
import none;
export filter {
if source = RTS_BGP then {
accept;
}
reject;
};
};
merge paths yes;
learn yes;
}
Device protocol for interface monitoring
protocol device {
scan time 10;
}
Direct protocol for connected routes
protocol direct {
ipv4;
ipv6;
interface "eth", "ens";
}
Static routes (if needed)
protocol static static4 {
ipv4;
# Add static routes here if needed
# route 192.168.1.0/24 via 203.0.113.1;
}
protocol static static6 {
ipv6;
# Add IPv6 static routes here if needed
}
Create BGP filter functions
Define reusable filter functions for common BGP route processing tasks.
# BGP Filter Functions
Function to check if route is a bogon (should not be advertised)
function is_bogon_prefix()
{
if net ~ [
0.0.0.0/8+, # RFC 1122 "this network"
10.0.0.0/8+, # RFC 1918 private
100.64.0.0/10+, # RFC 6598 Carrier Grade NAT
127.0.0.0/8+, # RFC 1122 loopback
169.254.0.0/16+, # RFC 3927 link local
172.16.0.0/12+, # RFC 1918 private
192.0.0.0/24+, # RFC 6890 IETF Protocol Assignments
192.0.2.0/24+, # RFC 5737 TEST-NET-1
192.168.0.0/16+, # RFC 1918 private
198.18.0.0/15+, # RFC 2544 benchmarking
198.51.100.0/24+, # RFC 5737 TEST-NET-2
203.0.113.0/24+, # RFC 5737 TEST-NET-3
224.0.0.0/4+, # RFC 3171 multicast
240.0.0.0/4+ # RFC 1112 reserved
] then return true;
return false;
}
Function to check valid AS path length
function is_valid_as_path_length()
{
if bgp_path.len > 64 then return false;
if bgp_path.len < 1 then return false;
return true;
}
Function to set BGP communities for route classification
function set_route_communities()
{
# Set informational communities
if source = RTS_STATIC then {
bgp_community.add((65000,100)); # Static route
}
if source = RTS_BGP then {
bgp_community.add((65000,200)); # BGP learned
}
return true;
}
Function for prefix length filtering
function is_valid_prefix_length()
{
# IPv4 prefix length limits
if net.type = NET_IP4 then {
if net.len < 8 then return false; # Too broad
if net.len > 24 then return false; # Too specific
}
# IPv6 prefix length limits
if net.type = NET_IP6 then {
if net.len < 12 then return false; # Too broad
if net.len > 48 then return false; # Too specific
}
return true;
}
Create import and export filters
Define sophisticated import and export filters for BGP route processing and security.
# BGP Import Filter
filter bgp_import_filter
{
# Reject bogon prefixes
if is_bogon_prefix() then {
print "Rejecting bogon prefix: ", net;
reject;
}
# Check AS path validity
if !is_valid_as_path_length() then {
print "Rejecting route with invalid AS path length: ", net;
reject;
}
# Check prefix length limits
if !is_valid_prefix_length() then {
print "Rejecting route with invalid prefix length: ", net;
reject;
}
# Reject routes with private AS numbers in path
if bgp_path ~ [64512..65534, 4200000000..4294967294] then {
print "Rejecting route with private AS in path: ", net;
reject;
}
# Set local preference based on communities
if bgp_community ~ [(65000,10)] then {
bgp_local_pref = 200; # Preferred routes
}
if bgp_community ~ [(65000,20)] then {
bgp_local_pref = 100; # Normal routes
}
if bgp_community ~ [(65000,30)] then {
bgp_local_pref = 50; # Backup routes
}
# Default local preference if not set
if bgp_local_pref = 0 then {
bgp_local_pref = 100;
}
set_route_communities();
accept;
}
BGP Export Filter
filter bgp_export_filter
{
# Only export our own prefixes and selected routes
if source != RTS_STATIC && source != RTS_BGP then {
reject;
}
# Don't export bogon prefixes
if is_bogon_prefix() then {
reject;
}
# Export policy based on communities
if bgp_community ~ [(65000,999)] then {
reject; # No-export community
}
# Set MED (Multi-Exit Discriminator) based on route type
if source = RTS_STATIC then {
bgp_med = 0; # Prefer static routes
} else {
bgp_med = 100; # BGP learned routes
}
# Prepend AS path for traffic engineering
if bgp_community ~ [(65000,666)] then {
bgp_path.prepend(bgp_local_as);
bgp_path.prepend(bgp_local_as);
}
accept;
}
Configure route aggregation policies
Set up route aggregation to reduce routing table size and improve network efficiency.
# Route Aggregation Configuration
Define aggregate routes
protocol static aggregates4 {
ipv4;
# Aggregate smaller prefixes into larger ones
# Example: aggregate /24 routes into /22
route 203.0.112.0/22 blackhole {
bgp_community.add((65000,500)); # Aggregated route marker
bgp_local_pref = 200;
};
}
protocol static aggregates6 {
ipv6;
# IPv6 aggregation example
route 2001:db8::/32 blackhole {
bgp_community.add((65000,500)); # Aggregated route marker
bgp_local_pref = 200;
};
}
Filter for aggregate route announcement
filter aggregate_export_filter
{
# Only announce aggregates if more specific routes exist
if bgp_community ~ [(65000,500)] then {
# Check if we have more specific routes in routing table
if source = RTS_STATIC then {
accept;
}
}
reject;
}
Configure BGP sessions with upstream providers
Set up BGP peering sessions with different types of neighbors including upstream providers and peers.
# Add this to the end of /etc/bird/bird.conf
BGP Session with Upstream Provider 1
protocol bgp upstream1 {
description "Upstream Provider 1";
local as 65001;
neighbor 203.0.113.1 as 174;
ipv4 {
import filter bgp_import_filter;
export filter bgp_export_filter;
next hop self;
};
# Connection parameters
hold time 180;
keepalive time 60;
connect retry time 30;
# Authentication (optional)
password "your_bgp_password_here";
# BGP attributes
default bgp_local_pref 100;
default bgp_med 0;
}
BGP Session with Peer Network
protocol bgp peer1 {
description "Peer Network 1";
local as 65001;
neighbor 203.0.113.2 as 65002;
ipv4 {
import filter {
# More restrictive import for peers
if is_bogon_prefix() then reject;
if !is_valid_prefix_length() then reject;
if bgp_path.len > 10 then reject; # Shorter AS paths only
bgp_local_pref = 150; # Prefer peer routes
set_route_communities();
accept;
};
export filter {
# Only export our own routes to peers
if source = RTS_STATIC then accept;
if bgp_community ~ [(65000,100)] then accept;
reject;
};
};
hold time 180;
keepalive time 60;
multihop 2;
}
BGP Session with Route Server (IX)
protocol bgp routeserver1 {
description "Internet Exchange Route Server";
local as 65001;
neighbor 203.0.113.254 as 65000; # Route server AS
ipv4 {
import filter {
# Accept diverse routes from route server
if is_bogon_prefix() then reject;
if !is_valid_as_path_length() then reject;
if !is_valid_prefix_length() then reject;
# Set local preference based on AS path length
if bgp_path.len <= 3 then bgp_local_pref = 120;
else if bgp_path.len <= 5 then bgp_local_pref = 110;
else bgp_local_pref = 100;
set_route_communities();
accept;
};
export filter bgp_export_filter;
add paths tx;
add paths rx;
};
rs client;
hold time 180;
keepalive time 60;
}
Configure advanced routing policies
Implement sophisticated routing policies for traffic engineering and redundancy.
# Advanced Routing Policies
Traffic Engineering Policy
filter traffic_engineering_policy
{
# Primary path selection
if bgp_community ~ [(65001,100)] then {
bgp_local_pref = 300; # Highest preference
accept;
}
# Secondary path with AS prepending
if bgp_community ~ [(65001,200)] then {
bgp_local_pref = 200;
# Prepend for outbound traffic engineering
bgp_path.prepend(bgp_local_as);
accept;
}
# Backup path
if bgp_community ~ [(65001,300)] then {
bgp_local_pref = 100;
# Heavy prepending for backup
bgp_path.prepend(bgp_local_as);
bgp_path.prepend(bgp_local_as);
bgp_path.prepend(bgp_local_as);
accept;
}
# Geographic-based routing
if bgp_community ~ [(65001,1001)] then { # European routes
bgp_local_pref = 250;
}
if bgp_community ~ [(65001,1002)] then { # US routes
bgp_local_pref = 150;
}
if bgp_community ~ [(65001,1003)] then { # Asian routes
bgp_local_pref = 120;
}
accept;
}
Load Balancing Policy
filter load_balancing_policy
{
# Enable ECMP for equal cost paths
if bgp_local_pref >= 200 then {
# Mark routes for ECMP consideration
bgp_community.add((65000,777));
}
# Weighted load balancing using communities
if bgp_community ~ [(65001,5000)] then {
bgp_local_pref = 200; # 50% traffic weight
}
if bgp_community ~ [(65001,3000)] then {
bgp_local_pref = 180; # 30% traffic weight
}
if bgp_community ~ [(65001,2000)] then {
bgp_local_pref = 160; # 20% traffic weight
}
accept;
}
Set up automated BGP monitoring and alerting
Create scripts for monitoring BGP session status and automated alerting.
#!/bin/bash
BIRD BGP Monitoring Script
LOG_FILE="/var/log/bird_monitor.log"
ALERT_EMAIL="admin@example.com"
Function to log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}
Check BIRD daemon status
check_bird_status() {
if ! systemctl is-active --quiet bird; then
log_message "ERROR: BIRD daemon is not running"
echo "BIRD daemon is down on $(hostname)" | mail -s "BIRD Alert" "$ALERT_EMAIL"
return 1
fi
return 0
}
Check BGP session status
check_bgp_sessions() {
local sessions_down=0
# Get BGP protocol status
while IFS= read -r line; do
if echo "$line" | grep -q "BGP.*down"; then
protocol_name=$(echo "$line" | awk '{print $1}')
log_message "WARNING: BGP session $protocol_name is down"
echo "BGP session $protocol_name is down on $(hostname)" | mail -s "BGP Session Alert" "$ALERT_EMAIL"
sessions_down=$((sessions_down + 1))
fi
done < <(birdc show protocols | grep -E "^(upstream|peer|routeserver)")
return $sessions_down
}
Check routing table size
check_routing_table_size() {
local route_count
route_count=$(birdc show route count | grep -o '[0-9]\+' | head -1)
if [ "$route_count" -lt 100 ]; then
log_message "WARNING: Low route count: $route_count"
echo "Low route count ($route_count) on $(hostname)" | mail -s "Routing Table Alert" "$ALERT_EMAIL"
fi
log_message "INFO: Current route count: $route_count"
}
Main monitoring logic
main() {
log_message "Starting BIRD monitoring check"
check_bird_status
if [ $? -eq 0 ]; then
check_bgp_sessions
check_routing_table_size
fi
log_message "BIRD monitoring check completed"
}
Run main function
main
Make monitoring script executable and set up cron job
Configure automated monitoring to run every 5 minutes.
sudo chmod +x /usr/local/bin/bird_monitor.sh
sudo chown bird:bird /usr/local/bin/bird_monitor.sh
Add cron job for automated monitoring
echo "/5 * /usr/local/bin/bird_monitor.sh" | sudo crontab -u bird -
Configure log rotation
Set up log rotation for BIRD logs to prevent disk space issues.
/var/log/bird.log /var/log/bird_monitor.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 bird bird
postrotate
systemctl reload bird
endscript
}
Enable and start BIRD service
Enable BIRD to start automatically on boot and start the service.
sudo systemctl enable bird
sudo systemctl start bird
sudo systemctl status bird
Verify your setup
Check that BIRD is running correctly and BGP sessions are established.
# Check BIRD daemon status
sudo systemctl status bird
Check BIRD configuration syntax
sudo bird -p
Access BIRD control interface
sudo birdc
Inside birdc, run these commands:
show status
show protocols
show protocols all bgp
show route
show route export upstream1
exit
Check routing table
ip route show
Verify BGP sessions
sudo birdc show protocols | grep BGP
Check route counts
sudo birdc show route count
Monitor logs
sudo tail -f /var/log/bird.log
sudo birdc show protocols all bgp to see detailed session status and troubleshoot connection issues.Advanced configuration examples
Route redistribution from OSPF
Example configuration for redistributing OSPF routes into BGP.
# Add OSPF protocol
protocol ospf v2 ospf_internal {
ipv4 {
import all;
export none;
};
area 0.0.0.0 {
interface "eth1" {
cost 10;
hello 10;
retransmit 5;
wait 40;
dead 40;
};
};
}
Modify BGP export filter to include OSPF routes
filter bgp_export_with_ospf
{
# Export static routes
if source = RTS_STATIC then accept;
# Export selected OSPF routes
if source = RTS_OSPF then {
# Only export specific OSPF networks
if net ~ [203.0.114.0/24, 203.0.115.0/24] then {
bgp_community.add((65000,300)); # OSPF redistributed
bgp_med = 200;
accept;
}
}
reject;
}
Conditional route advertisement
Configure conditional advertisement based on route existence.
# Conditional Advertisement Policy
filter conditional_advertisement
{
# Only advertise aggregate if more specific routes exist
if net = 203.0.112.0/22 then {
# Check if any /24 within aggregate exists
if exists(203.0.112.0/24) || exists(203.0.113.0/24) ||
exists(203.0.114.0/24) || exists(203.0.115.0/24) then {
bgp_community.add((65000,600)); # Conditional route
accept;
}
reject;
}
# Normal processing for other routes
accept;
}
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| BGP sessions won't establish | Firewall blocking TCP/179 or wrong neighbor IP | Check sudo ufw allow 179/tcp and verify neighbor configuration |
| "Configuration file syntax error" | Missing semicolons or bracket mismatch | Run sudo bird -p to check syntax |
| Routes not being advertised | Export filter rejecting routes | Check export filter logic and use birdc show route export protocol_name |
| BIRD daemon crashes on startup | Invalid router ID or interface issues | Check router ID matches real interface IP and interfaces exist |
| No routes in kernel table | Kernel protocol not exporting BGP routes | Verify kernel protocol export filter allows source = RTS_BGP |
| High memory usage | Large routing tables with full BGP feeds | Implement prefix filtering and route aggregation |
| Session flapping | Hold timer too low or network instability | Increase hold time to 180+ seconds and check network connectivity |
Performance optimization
Memory and CPU tuning
Optimize BIRD for handling large routing tables and high session counts.
# Add these settings to improve performance
Increase protocol processing timeouts
timeformat protocol short;
Optimize memory usage for large tables
table master4 {
# Pre-allocate memory for better performance
gc threshold 10000;
gc period 300;
};
Enable multi-threading for route processing (BIRD 2.0.8+)
protocol kernel kernel4 {
ipv4 {
import none;
export all;
};
scan time 20;
merge paths yes;
kernel table 254;
}
Monitoring BGP performance
Advanced monitoring integration with external systems.
#!/bin/bash
Export BIRD metrics for monitoring systems
BGP session count by state
echo "# HELP bird_bgp_sessions_total Total BGP sessions by state"
echo "# TYPE bird_bgp_sessions_total gauge"
birdc show protocols | grep -c "BGP.*up" | sed 's/^/bird_bgp_sessions_total{state="up"} /'
birdc show protocols | grep -c "BGP.*down" | sed 's/^/bird_bgp_sessions_total{state="down"} /'
Route count
echo "# HELP bird_routes_total Total routes in routing table"
echo "# TYPE bird_routes_total gauge"
birdc show route count | grep -o '[0-9]\+' | head -1 | sed 's/^/bird_routes_total /'
Memory usage
echo "# HELP bird_memory_usage_bytes BIRD memory usage in bytes"
echo "# TYPE bird_memory_usage_bytes gauge"
birdc show memory | grep 'Routing tables' | awk '{print "bird_memory_usage_bytes{type=\"routing_tables\"}", $4*1024}'
birdc show memory | grep 'Route attributes' | awk '{print "bird_memory_usage_bytes{type=\"route_attributes\"}", $4*1024}'
You can integrate BIRD monitoring with existing infrastructure using tools covered in our Prometheus and Grafana monitoring guides or centralized logging setup.
Next steps
- Configure OSPF with FRRouting for internal network routing
- Implement advanced firewall rules for BGP traffic filtering
- Set up RPKI validation for enhanced BGP security
- Configure BGP multipath load balancing with BIRD
- Advanced BGP communities and traffic engineering with BIRD