bird-openwrt: update to version 0.3
[feed/routing.git] / bird-openwrt / bird6-openwrt / src / init.d / bird6
index ed99d27..32e16a9 100755 (executable)
@@ -1,7 +1,6 @@
 #!/bin/sh /etc/rc.common
 
-# Copyright (C) 2014 - Eloi Carbó Solé (GSoC2014) 
-# BGP/Bird integration with OpenWRT and QMP
+# Copyright (C) 2014-2017 - Eloi Carbo
 #
 # 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
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
+# Extra Service Function to get the Status of the Service
+# This complements /etc/rc.common functions
+# Commands ending with *_quiet are meant to be ran in Luci. These
+# scripts' return minimal output.
+EXTRA_COMMANDS="status start_quiet stop_quiet restart_quiet status_quiet"
+EXTRA_HELP="        status  Returns service status"
+
 BIRD="bird6"
-BIRD_CONFIG="/etc/$BIRD.conf"
+BIRD_CONFIG="/etc/${BIRD}.conf"
+BIRD_LOG="/var/log/${BIRD}.log"
+BIRD_ERR="/tmp/${BIRD}.err"
 
 START=99
 STOP=10
 
 SERVICE_DAEMONIZE=1
 SERVICE_USE_PID=1
-SERVICE_PID_FILE="/var/run/$BIRD.pid"
-
-BIRD_BIN="/usr/sbin/$BIRD"
+SERVICE_PID_FILE="/var/run/${BIRD}.pid"
 
+BIRD_BIN="/usr/sbin/${BIRD}"
+# Special non-terminal-rich output for Luci calls
+LUCI="false"
 
-# 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
-}
+. /etc/${BIRD}/init.d/${BIRD}-lib.sh
 
-# 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"
-}
+start() {
+    config_load ${BIRD}
+    local use_UCI_config
+    get use_UCI_config 'bird'
 
-#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;"
-}
+    #Start the service
+    if [ "${LUCI}" == "false" ]; then
+        echo "Starting ${BIRD} Service [ ... ]"
+    fi
+    if [ -f ${BIRD_ERR} ]; then
+        echo "" > ${BIRD_ERR}
+    else
+        touch ${BIRD_ERR}
+    fi
 
-# 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
-}
+    if [ -z "${use_UCI_config}" -o "${use_UCI_config}" = "0" ]; then
+        # Disable Custom bird-openwrt settings.
+        # Use default behaviour and files
+        ${BIRD_BIN} -d -c ${BIRD_CONFIG} -P ${SERVICE_PID_FILE} -D ${BIRD_LOG} &> ${BIRD_ERR} &
+    else
+        #Set Bird6 configuration location:
+        local UCI_config_file
+        local log_file
+        get UCI_config_file 'bird'
+        get log_file 'global'
+        BIRD_CONFIG="${UCI_config_file:-$BIRD_CONFIG}"
+        BIRD_LOG="${log_file:-$BIRD_LOG}"
+        #Backup previous configuration
+        [ -f ${BIRD_CONFIG} ] && cp ${BIRD_CONFIG} ${BIRD_CONFIG}.bak
+        #Setup the basic configuration
+        prepare_global 'global'
 
-# 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
-}
+        # Gather and set all Functions
+        gather_functions
+        # Gather and set all Filters
+        gather_filters
 
-# Function: multipath_list $1
-# $1 string
-# This function writes the $1 string in the multipath routes.
-multipath_list() {
-    write "          via $1" $1
-}
+        # Setup Main Protocols
+        config_foreach prepare_kernel 'kernel'
+        config_foreach prepare_static 'static'
+        config_foreach prepare_device 'device'
+        config_foreach prepare_direct 'direct'
+        config_foreach prepare_pipe 'pipe'
 
-# Function: prepare_tables $1
-# $1 string
-# This function gets each "table" section in the UCI configuration and sets each option in the bird6.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
-}
+        #Setup protocol's configuration: BGP
+        config_foreach prepare_bgp_template 'bgp_template'
+        config_foreach prepare_bgp 'bgp'
 
-# Function: prepare_global $1
-# $1 string
-# This function gets each "global" section in the UCI configuration and sets each option in the bird6.conf file.
-# $1 is set as the ID of the current UCI global section. prepare_global is the first configuration set in the bird6.conf and removes the old file.
-prepare_global () {
-    local section="$1"
-    local log_file; local log; local debug; local router_id; local table; local listen_bgp_addr; local listen_bgp_port; local listen_bgp_dual
+        #Setup protocol's configuration: OSPF
+        #config_foreach prepare_ospf_instance 'ospf'
 
-    # 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
-    get listen_bgp_addr $section
-    get listen_bgp_port $section
-    get listen_bgp_dual $section
-    
-    # First line of the NEW configuration file
-    echo "#Bird6 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'
-    if [ -n "$listen_bgp_dual" -o "$listen_bgp_dual" = "0" ]; then
-        writeToConfig "listen bgp $listen_bgp_addr $listen_bgp_port v6only;"
-    else
-        writeToConfig "listen bgp $listen_bgp_addr $listen_bgp_port dual;"
+        #Start the service
+        ${BIRD_BIN} -d -c ${BIRD_CONFIG} -P ${SERVICE_PID_FILE} -D ${BIRD_LOG} &>${BIRD_ERR} &
     fi
-    writeToConfig " "
-}
-
-# Function: prepare_routes $1
-# $1 string
-# This function gets each "route" section in the UCI configuration and sets each option in the bird6.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
+    while [ ! -s ${SERVICE_PID_FILE} ]; do
+        sleep 1
+        if [ -s ${BIRD_ERR} ]; then
+            if [ "${LUCI}" == "false" ]; then
+                echo -e "${BIRD} Daemon Start Status: \033[0;31m[ FAILED ]\e[m"
+                cat ${BIRD_ERR}
+                cat ${BIRD_ERR} >> ${BIRD_LOG}
+            else
+                echo "${BIRD} - Failed: $(cat ${BIRD_ERR})"
+                cat ${BIRD_ERR} >> ${BIRD_LOG}
+            fi
+            break
+        fi
+    done
+
+    if [ -s ${SERVICE_PID_FILE} ]; then
+        if [ -s ${BIRD_ERR} ]; then
+            if [ "${LUCI}" == "false" ]; then
+                echo -e "${BIRD} Daemon already started. Status \033[0;32m[ RUNNING ]\e[m"
+            else
+                echo "${BIRD} already started"
+            fi
+        else
+            if [ "${LUCI}" == "false" ]; then
+                echo -e "${BIRD} Daemon Start Status: \033[0;32m[ STARTED ]\e[m"
+            else
+                echo "${BIRD} - Started"
+            fi
+        fi
+        # PID File found (service started correctly)
+        return 0
     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 " "
+    # PID File not found (error while starting service)
+    return 1
 }
 
-# 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 " "
+stop() {
+    if [ -s ${SERVICE_PID_FILE} ]; then
+        config_load ${BIRD}
+        local log_file
+        get log_file 'global'
+        BIRD_LOG="${log_file:-$BIRD_LOG}"
+        start-stop-daemon -p ${SERVICE_PID_FILE} -K 2>&1 >> ${BIRD_LOG}
+        if [ $? -eq 0 ]; then
+            if [ "${LUCI}" == "false" ]; then
+                echo -e "${BIRD} Daemon Stop Status: \033[0;32m[ OK ]\e[m"
+            else
+                echo "${BIRD} - Stopped"
+            fi
+        else
+            if [ "${LUCI}" == "false" ]; then
+                echo -e "${BIRD} Daemon Stop Status: \033[0;31m[ FAILED ]\e[m"
+                echo "Check ${BIRD_LOG} file for more information."
+            else
+                echo "${BIRD} Failed to Stop. See Log file: ${BIRD_LOG}"
+            fi
+        fi
+    else
+        if [ "${LUCI}" == "false" ]; then
+            echo -e "${BIRD} Daemon Service already stopped. \033[0;31m[ FAILED ]\e[m"
+        else
+            echo "${BIRD} already stopped"
+        fi
     fi
+    return 0
 }
 
-# Function: prepare_device $1
-# $1 string
-# This function gets each "device" 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 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 bird6.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;"
+restart() {
+    stop
+    sleep 1
+    if [ "${LUCI}" == "true" ]; then
+        echo " ... "
     fi
-    [ -n "$neighbor_address" -a -n "$neighbor_as" ] && writeToConfig "    neighbor $neighbor_address as $neighbor_as;"
-    writeToConfig "}"
-    writeToConfig " "
+    start
 }
 
-# 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 " "
+reload() {
+    service_reload ${BIRD_BIN}
 }
 
-# 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 bird6.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 " "
+status() {
+    if [ -s ${SERVICE_PID_FILE} ]; then
+        if [ "${LUCI}" == "false" ]; then
+            echo -e "${BIRD} start status: \033[0;32m[ RUNNING ]\e[m"
+        else
+            echo "${BIRD}: Running"
         fi
-    fi
-}
-
-
-start() {
-    config_load bird6
-    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
+        return 0
     else
-        #Set Bird6 configuration location:
-        local UCI_config_File
-        get UCI_config_File 'bird'
-        BIRD_CONFIG=${UCI_config_File:-/tmp/bird6.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
+        if [ -s ${BIRD_ERR} ]; then
+            if [ "${LUCI}" == "false" ]; then
+                echo -e "${BIRD} service status: \033[0;31m[ STOPPED ]\e[m"
+                cat ${BIRD_ERR}
+            else
+                echo "${BIRD}: Failed - $(cat ${BIRD_ERR})"
+            fi
+            return 2
+        else
+            if [ "${LUCI}" == "false" ]; then
+                echo -e "${BIRD} service status: \033[0;31m[ STOPPED ]\e[m"
+            else
+                echo "${BIRD}: Stopped"
+            fi
+            return 1
+        fi
     fi
 }
 
-stop() {
-    service_stop $BIRD_BIN
+# Luci-specific calls (stripped output).
+# The following scripts are not meant to be ran using Ash Terminal
+# Used in: LUCI/model/cbi/bird6/status.lua
+start_quiet() {
+    LUCI="true"
+    start
 }
-
-restart() {
+stop_quiet() {
+    LUCI="true"
     stop
-    start
 }
-
-
-reload() {
-    service_reload $BIRD_BIN
+restart_quiet() {
+    LUCI="true"
+    restart
+}
+status_quiet() {
+    LUCI="true"
+    status
 }