#!/bin/sh /etc/rc.common # Copyright (C) 2014 - Eloi Carbó Solé (GSoC2014) # BGP/Bird integration with OpenWRT and QMP # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # BIRD="bird4" BIRD_CONFIG="/etc/$BIRD.conf" START=99 STOP=10 SERVICE_DAEMONIZE=1 SERVICE_USE_PID=1 SERVICE_PID_FILE="/var/run/$BIRD.pid" BIRD_BIN="/usr/sbin/$BIRD" # Function: writeToConfig $1 # $1 string. # Allows to write in the $BIRD_CONFIG file, the string $1. This function does not check the $1 string. # Example: writeToConfig "value: $N" writeToConfig() { echo "$1" >> $BIRD_CONFIG } # Function: write $1 $2 # $1 string. $2 string. # This function checks if $2 is empty. If not, it writes the string $1 in the $BIRD_CONFIG file. # Use write function to check if $1, value found inside $2, is not empty and can be written in the configuration file. # Example: N=""; write "value: $N" $N; write() { [ -n "$2" ] && writeToConfig "$1" } #Function: write_bool $1 $2 # $1 string; $2 boolean # This function checks if $2 is true or false and write the $1 string into $BIRD_CONFIG file. # The function writes a # before the $2 string if its false. # Example: local N=0; write_bool $N write_bool() { [ "$2" == 0 ] && writeToConfig "# $1;" || writeToConfig " $1;" } # Function: get $1 $2 # $1 string. $2 string # This function uses the external UCI function "config_get $result $section $option" to obtain a string value from UCI config file. # To use this function, use the same name of the UCI option for the variable. # Example: UCI (option id 'abcd'); local id; get id $section get() { config_get $1 $2 $1 } # Function: get_bool $1 $2 # $1 boolean. $2 string # This function uses the external UCI function "config_get_bool $result $section $option" to obtain a boolean value from UCI config file. # To use this function, use the same name of the UCI option for the variable $1. # Example: UCI (option use_ipv6 '1'); local use_ipv6; get use_ipv6 $section get_bool() { config_get_bool $1 $2 $1 } # Function: multipath_list $1 # $1 string # This function writes the $1 string in the multipath routes. multipath_list() { write " via $1" $1 } # Function: prepare_tables $1 # $1 string # This function gets each "table" section in the UCI configuration and sets each option in the bird4.conf file. # $1 is set as the ID of the current UCI table section prepare_tables() { local section="$1"; local name get name $section write "table $name;" $name } # Function: prepare_global $1 # $1 string # This function gets each "global" section in the UCI configuration and sets each option in the bird4.conf file. # $1 is set as the ID of the current UCI global section. prepare_global is the first configuration set in the bird4.conf and removes the old file. prepare_global () { local section="$1" local log_file; local log; local debug; local router_id; local table # Remove old configuration file rm -f "$BIRD_CONFIG" get log_file $section get log $section get debug $section get router_id $section get table $section # First line of the NEW configuration file echo "#Bird4 configuration using UCI:" > $BIRD_CONFIG writeToConfig " " [ -n "$log_file" -a -n "$log" ] && writeToConfig 'log "'$log_file'" '$log';' write "debug protocols $debug;" $debug writeToConfig " " writeToConfig "#Router ID" write "router id $router_id;" $router_id writeToConfig " " writeToConfig "#Secondary tables" config_foreach prepare_tables 'table' writeToConfig " " } # Function: prepare_routes $1 # $1 string # This function gets each "route" section in the UCI configuration and sets each option in the bird4.conf file. # $1 is set as the ID of the current UCI route section. Each type of route has its own treatment. prepare_routes() { local instance; local prefix; local via; local type local section="$1" local protoInstance="$2" get instance $section if [ "$instance" = "$protoInstance" ]; then get type $section case "$type" in "router") get prefix $section get via $section [ -n "$prefix" -a -n "$via" ] && writeToConfig " route $prefix via $via;" ;; "special") get prefix $section get attribute $section [ -n "$prefix" -a -n "$attribute" ] && writeToConfig " route $prefix $attribute;" ;; "iface") get prefix $section get iface $section [ -n "$prefix" -a -n "$iface" ] && writeToConfig ' route '$prefix' via "'$iface'";' ;; "multipath") get prefix $section write " route $prefix multipath" $prefix config_list_foreach $section l_via multipath_list writeToConfig " ;" ;; esac fi } # Function: prepare_kernel $1 # $1 string # This function gets each "kernel" protocol section in the UCI configuration and sets each option in the bird6.conf file. # $1 is set as the ID of the current UCI kernel section. prepare_kernel() { local section="$1" write "#$section configuration:" $section local disabled; local table; local kernel_table; local import; local export; local scan_time; local persist; local learn get_bool disabled $section get table $section get import $section get export $section get scan_time $section get kernel_table $section get learn $section get persist $section writeToConfig "protocol kernel {" write_bool disabled $disabled write " table $table;" $table write " kernel table $kernel_table;" $kernel_table write_bool learn $learn write_bool persist $persist write " scan time $scan_time;" $scan_time write " import $import;" $import write " export $export;" $export writeToConfig "}" writeToConfig " " } # Function: prepare_static $1 # $1 string # This function gets each "static" protocol section in the UCI configuration and sets each option in the bird6.conf file. # $1 is set as the ID of the current UCI static section. prepare_static() { local section="$1" local disabled get disabled $section if [ "$disabled" -eq 0 ]; then local table get table $section writeToConfig "#$section configration:" $section writeToConfig "protocol static {" write " table $table;" $table config_foreach prepare_routes 'route' $section writeToConfig "}" writeToConfig " " fi } # Function: prepare_device $1 # $1 string # This function gets each "device" protocol section in the UCI configuration and sets each option in the bird4.conf file. # $1 is set as the ID of the current UCI device section. prepare_device() { local section="$1" local disabled; local scan_time get disabled $section get scan_time $section write "#$section configuration:" $section writeToConfig "protocol device {" write_bool disabled $disabled write " scan time $scan_time;" $scan_time writeToConfig "}" writeToConfig " " } # Function: prepare_bgp_template $1 # $1 string # This function gets each "bgp_template" protocol section in the UCI configuration and sets each option in the bird4.conf file. # $1 is set as the ID of the current UCI bgp_template section. # Careful! Template options will be replaced by "instance" options if there is any match. prepare_bgp_template() { local section="$1" local disabled; local table; local import; local export; local local_address; local local_as; local neighbor_address; local neighbor_as; local source_address; local next_hop_self; local next_hop_keep; local rr_client; local rr_cluster_id; local import_limit; local import_limit_action; local export_limit; local export_limit_action; local receive_limit; local receive_limit_action get_bool disabled $section get_bool next_hop_self $section get_bool next_hop_keep $section get table $section get import $section get export $section get local_address $section get local_as $section get rr_client $section get rr_cluster_id $section get import_limit $section get import_limit_action $section get export_limit $section get export_limit_action $section get receive_limit $section get receive_limit_action $section get neighbor_address $section get neighbor_as $section writeToConfig "#$section template:" writeToConfig "template bgp $section {" [ -n "$disabled" ] && write_bool disabled $disabled write " table $table;" $table write " local as $local_as;" $local_as write " source address $local_address;" $local_address write " import $import;" $import write " export $export;" $export if [ -n "$next_hop_self" ]; then [ "$next_hop_self" = "1" ] && writeToConfig " next hop self;" || writeToConfig "# next hop self;" fi if [ -n "$next_hop_keep" ]; then [ "$next_hop_keep" = "1" ] && writeToConfig " next hop keep;" || writeToConfig "# next hop keep;" fi [ "$rr_client" = "1" ] && writeToConfig " rr client;" || writeToConfig "# rr client;" write " rr cluster id $rr_cluster_id;" $rr_cluster_id if [ -n "$import_limit" -a "$import_limit" > "0" ]; then [ -z "$import_limit_action" ] && $import_limit_action = "warn" writeToConfig " import limit $import_limit action $import_limit_action;" fi if [ -n "$export_limit" -a "$export_limit" > "0" ]; then [ -z "$export_limit_action" ] && $export_limit_action = "warn" writeToConfig " export limit $export_limit action $export_limit_action;" fi if [ -n "$receive_limit" -a "$receive_limit" > "0" ]; then [ -z "$receive_limit_action" ] && $receive_limit_action = "warn" writeToConfig " receive limit $receive_limit action $receive_limit_action;" fi [ -n "$neighbor_address" -a -n "$neighbor_as" ] && writeToConfig " neighbor $neighbor_address as $neighbor_as;" writeToConfig "}" writeToConfig " " } # Function: prepare_bgp $1 # $1 string # This function gets each "bgp" protocol section in the UCI configuration and sets each option in the bird6.conf file. # $1 is set as the ID of the current UCI bgp section. # Careful! The options set in bgp instances overlap bgp_template ones. prepare_bgp() { local section="$1" local disabled; local table; local template; local description; local import; local export; local local_address; local local_as; local neighbor_address; local neighbor_as; local rr_client; local rr_cluster_id; local import_limit; local import_limit_action; local export_limit; local export_limit_action; local receive_limit; local receive_limit_action get disabled $section get table $section get template $section get description $section get import $section get export $section get local_address $section get local_as $section get rr_client $section get rr_cluster_id $section get import_limit $section get import_limit_action $section get export_limit $section get export_limit_action $section get receive_limit $section get receive_limit_action $section get neighbor_address $section get neighbor_as $section writeToConfig "#$section configuration:" [ -n "$template" ] && writeToConfig "protocol bgp $section from $template {" || writeToConfig "protocol bgp $section {" [ -n "$disabled" ] && write_bool disabled $disabled write " table $table;" $table # [ -n "$description" ] && writeToConfig ' description "'$description'";' write " local as $local_as;" $local_as write " source address $local_address;" $local_address write " import $import;" $import write " export $export;" $export if [ -n "$next_hop_self" ]; then [ "$next_hop_self" = "1" ] && writeToConfig " next hop self;" || writeToConfig "# next hop self;" fi if [ -n "$next_hop_keep" ]; then [ "$next_hop_keep" = "1" ] && writeToConfig " next hop keep;" || writeToConfig "# next hop keep;" fi [ "$rr_client" = "1" ] && writeToConfig " rr client;" || writeToConfig "# rr client;" write " rr cluster id $rr_cluster_id;" $rr_cluster_id if [ -n "$import_limit" -a "$import_limit" > "0" ]; then [ -z "$import_limit_action" ] && $import_limit_action = "warn" writeToConfig " import limit $import_limit action $import_limit_action;" fi if [ -n "$export_limit" -a "$export_limit" > "0" ]; then [ -z "$export_limit_action" ] && $export_limit_action = "warn" writeToConfig " export limit $export_limit action $export_limit_action;" fi if [ -n "$receive_limit" -a "$receive_limit" > "0" ]; then [ -z "$receive_limit_action" ] && $receive_limit_action = "warn" writeToConfig " receive limit $receive_limit action $receive_limit_action;" fi [ -n "$neighbor_address" -a -n "$neighbor_as" ] && writeToConfig " neighbor $neighbor_address as $neighbor_as;" writeToConfig "}" writeToConfig " " } # Function: prepare_bgp_filters $1 # $1 string # This function gets each "bgp_filter" protocol section in the UCI configuration and sets each option in the bird4.conf file. # $1 is set as the ID of the current UCI bgp_filter section. # This function checks if the filter file exists and, in that case, it writes its content to the configuration file. prepare_bgp_filters() { local section="$1" local type local file_path get type $section get file_path $section if [ -e "$file_path" ]; then local filter_content=`cat $file_path` if [ -n "$type" -a "$type" = "bgp" ]; then writeToConfig "#Filter $section:" writeToConfig "${filter_content}" writeToConfig " " fi fi } start() { config_load bird4 local use_UCI_config get use_UCI_config 'bird' if [ -z "$use_UCI_config" -o "$use_UCI_config" = "0" ]; then service_start $BIRD_BIN -d -c $BIRD_CONFIG -P $SERVICE_PID_FILE else #Set Bird4 configuration location: local UCI_config_File get UCI_config_File 'bird' BIRD_CONFIG=${UCI_config_File:-/tmp/bird4.conf} #Setup the basic configuration prepare_global 'global' config_foreach prepare_kernel 'kernel' config_foreach prepare_static 'static' config_foreach prepare_device 'device' #config_foreach prepare_direct 'direct' #Setup the protocols configuration (currently BGP only) config_foreach prepare_bgp_template 'bgp_template' config_foreach prepare_bgp 'bgp' config_foreach prepare_bgp_filters 'filter' #Start the service service_start $BIRD_BIN -d -c $BIRD_CONFIG -P $SERVICE_PID_FILE fi } stop() { service_stop $BIRD_BIN } restart() { stop start } reload() { service_reload $BIRD_BIN }