#!/bin/sh /etc/rc.common # Copyright (C) 2007-2015 OpenWrt.org START=70 STOP=01 USE_PROCD=1 KEEPALIVED_CONF=/tmp/keepalived.conf INDENT_1=\\t INDENT_2=$INDENT_1$INDENT_1 config_section_open() { local tag=$1 local name=$2 printf "$tag" >> $KEEPALIVED_CONF [ -n "$name" ] && printf " $name" >> $KEEPALIVED_CONF printf " {\n" >> $KEEPALIVED_CONF } config_section_close() { printf "}\n\n" >> $KEEPALIVED_CONF } config_foreach_wrapper() { local section=$1 local function=$1 # Convention is that 'function' and 'section' are the same config_foreach $function $section } print_elems_indent() { local config=$1 shift local indent=$1 shift [ -z "$indent" ] && indent="$INDENT_1" for opt in $*; do local $opt local no_val=0 if [ ${opt:0:7} == "no_val_" ]; then opt=${opt:7} no_val=1 fi config_get $opt $config $opt eval optval=\$$opt [ -z "$optval" ] && continue printf "$indent$opt" >> $KEEPALIVED_CONF [ "$no_val" == "0" ] && { local words=$(echo "$optval" | wc -w) if [ $words -gt 1 ]; then printf " \"$optval\"" >> $KEEPALIVED_CONF else printf " $optval" >> $KEEPALIVED_CONF fi } printf "\n" >> $KEEPALIVED_CONF done unset optval } print_list_indent() { local lst=$1 local indent=$2 local lst_elems [ -z "$indent" ] && indent=$INDENT_1 eval lst_elems=\$$lst [ -z "$lst_elems" ] && return 0 printf "$indent$lst {\n" >> $KEEPALIVED_CONF for e in $lst_elems; do [ -n "$eval_item_func" ] printf "$indent$INDENT_1$e\n" >> $KEEPALIVED_CONF done printf "$indent}\n" >> $KEEPALIVED_CONF } print_notify() { local type=$1 shift local name=$1 shift for notify in $*; do printf "$INDENT_1$notify" >> $KEEPALIVED_CONF notify=$(echo $notify | tr 'a-z' 'A-Z') printf " \"/bin/busybox env -i ACTION=$notify TYPE=$type NAME=$name /sbin/hotplug-call keepalived\"\n" >> $KEEPALIVED_CONF done } global_defs() { local linkbeat_use_polling notification_email config_get alt_config_file $1 alt_config_file [ -z "$alt_config_file" ] || return 0 config_get_bool linkbeat_use_polling $1 linkbeat_use_polling 0 [ $linkbeat_use_polling -gt 0 ] && printf "linkbeat_use_polling\n\n" >> $KEEPALIVED_CONF config_get notification_email $1 notification_email print_list_indent notification_email print_elems_indent $1 $INDENT_1 notification_email_from smtp_server smtp_connect_timeout \ router_id vrrp_mcast_group4 vrrp_mcast_group6 } print_ipaddress_indent() { local section=$1 local curr_ipaddr=$2 local indent=$3 local address device scope name config_get name $section name [ "$name" != "$curr_ipaddr" ] && return 0 config_get address $section address config_get device $section device config_get scope $section scope # Default indent [ -z "$indent" ] && indent=$INDENT_1 # If no address exit [ -z "$address" ] && return 0 if [ -z "$device" ]; then printf "$indent$address" >> $KEEPALIVED_CONF else # Add IP address/netmask and device printf "$indent$address dev $device" >> $KEEPALIVED_CONF # Add scope [ -n "$scope" ] && printf " scope $scope" >> $KEEPALIVED_CONF fi printf "\n" >> $KEEPALIVED_CONF } static_ipaddress() { local address config_get address "$1" address for a in $address; do config_foreach print_ipaddress_indent ipaddress $a done } print_route_indent() { local section=$1 local curr_route=$2 local indent=$3 local name blackhole address src_addr gateway device scope table config_get name $section name [ "$name" != "$curr_route" ] && return 0 config_get_bool blackhole $section blackhole 0 config_get address $section address config_get src_addr $section src_addr config_get gateway $section gateway config_get device $section device config_get table $section table # If no address exit [ -z "$address" ] && return 0 # Default indent [ -z "$indent" ] && indent=$INDENT_1 [ $blackhole -gt 0 ] && { printf "${indent}blackhole $address\n" >> $KEEPALIVED_CONF return 0 } # Add src addr or address if [ -n "$src_addr" ]; then printf "${indent}src $src_addr $address" >> $KEEPALIVED_CONF else [ -z "$device" ] && return 0 printf "$indent$address" >> $KEEPALIVED_CONF fi # Add route/gateway [ -n "$gateway" ] && printf " via $gateway" >> $KEEPALIVED_CONF # Add device printf " dev $device" >> $KEEPALIVED_CONF # Add scope [ -n "$scope" ] && printf " scope $scope" >> $KEEPALIVED_CONF # Add table [ -n "$table" ] && printf " table $table" >> $KEEPALIVED_CONF printf "\n" >> $KEEPALIVED_CONF } print_track_elem_indent() { local section=$1 local curr_track_elem=$2 local indent=$3 local script name value config_get name $section name [ "$name" != "$curr_track_elem" ] && return 0 config_get value $section value config_get weight $section weight [ -z "$value" ] && return 0 printf "$indent$value" >> $KEEPALIVED_CONF [ -n "$weight" ] && printf " weight $weight" >> $KEEPALIVED_CONF printf "\n" >> $KEEPALIVED_CONF } static_routes() { local route config_get route "$1" route for r in $route; do config_foreach print_route_indent route $r done } # Count 'vrrp_instance' with the given name ; called by vrrp_instance_check() vrrp_instance_name_count() { local name config_get name $1 name [ "$name" == "$2" ] && count=$((count + 1)) } # Check if there's a 'vrrp_instance' section with the given name vrrp_instance_check() { local count=0 local name=$1 config_foreach vrrp_instance_name_count vrrp_instance $name [ $count -gt 0 ] && return 0 || return 1 } vrrp_sync_group() { local group name local valid_group # No name for group, exit config_get name $1 name [ -z "$name" ] && return 0 # No members for group, exit config_get group $1 group [ -z "$group" ] && return 0 # Check if we have 'vrrp_instance's defined for # each member and remove names with not vrrp_instance defined for m in $group; do vrrp_instance_check $m && valid_group="$valid_group $m" done [ -z "$valid_group" ] && return 0 config_section_open "vrrp_sync_group" "$name" group="$valid_group" print_list_indent group print_elems_indent $1 $INDENT_1 no_val_smtp_alert no_val_global_tracking print_notify "GROUP" "$name" notify_backup notify_master \ notify_fault notify config_section_close } vrrp_instance() { local name auth_type auth_pass config_get name $1 name [ -z "$name" ] && return 0 config_section_open "vrrp_instance" "$name" config_get auth_type $1 auth_type config_get auth_pass $1 auth_pass [ -n "$auth_type" -a -n "$auth_pass" ] && { printf "${INDENT_1}authentication {\n" >> $KEEPALIVED_CONF printf "${INDENT_2}auth_type $auth_type\n" >> $KEEPALIVED_CONF printf "${INDENT_2}auth_pass $auth_pass\n" >> $KEEPALIVED_CONF printf "$INDENT_1}\n" >> $KEEPALIVED_CONF } print_elems_indent $1 $INDENT_1 state interface \ mcast_src_ip unicast_src_ip virtual_router_id version priority \ advert_int preempt_delay debug \ lvs_sync_daemon_interface garp_master_delay garp_master_refresh \ garp_master_repeat garp_master_refresh_repeat \ no_val_vmac_xmit_base no_val_native_ipv6 no_val_accept \ no_val_dont_track_primary no_val_smtp_alert no_val_nopreempt \ no_val_use_vmac print_notify "INSTANCE" "$name" notify_backup notify_master \ notify_fault notify_stop # Handle virtual_ipaddress & virtual_ipaddress_excluded lists for opt in virtual_ipaddress virtual_ipaddress_excluded; do config_get $opt $1 $opt eval optval=\$$opt [ -z "$optval" ] && continue printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF for a in $optval; do config_foreach print_ipaddress_indent ipaddress $a $INDENT_2 done printf "$INDENT_1}\n" >> $KEEPALIVED_CONF done # Handle virtual_routes for opt in virtual_routes; do config_get $opt $1 $opt eval optval=\$$opt [ -z "$optval" ] && continue printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF for r in $optval; do config_foreach print_route_indent route $r $INDENT_2 done printf "$INDENT_1}\n" >> $KEEPALIVED_CONF done # Handle track_script lists for opt in track_script; do config_get $opt $1 $opt eval optval=\$$opt [ -z "$optval" ] && continue printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF for t in $optval; do printf "$INDENT_2$optval\n" >> $KEEPALIVED_CONF done printf "$INDENT_1}\n" >> $KEEPALIVED_CONF done # Handle track_interface lists for opt in track_interface; do config_get $opt $1 $opt eval optval=\$$opt [ -z "$optval" ] && continue printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF for t in $optval; do config_foreach print_track_elem_indent track_interface $t $INDENT_2 done printf "$INDENT_1}\n" >> $KEEPALIVED_CONF done # Handle simple lists of strings (with no spaces in between) for opt in unicast_peer; do config_get $opt $1 $opt print_list_indent $opt done unset optval config_section_close } vrrp_script() { local name config_get name $1 name [ -z "$name" ] && return 0 config_section_open "vrrp_script" "$name" print_elems_indent $1 $INDENT_1 script interval weight fall rise config_section_close } process_config() { local alt_config_file rm -f $KEEPALIVED_CONF # First line printf "! Configuration file for keepalived (autogenerated via init script)\n" > $KEEPALIVED_CONF printf "! Written %s\n\n" "$(date +'%c')" >> $KEEPALIVED_CONF [ -f /etc/config/keepalived ] || return 0 config_load 'keepalived' config_section_open "global_defs" config_foreach_wrapper global_defs config_section_close # If "alt_config_file" specified, use that instead [ -n "$alt_config_file" ] && [ -f "$alt_config_file" ] && { rm -f $KEEPALIVED_CONF # Symlink "alt_config_file" since it's a bit easier and safer ln -s $alt_config_file $KEEPALIVED_CONF return 0 } config_section_open "static_ipaddress" config_foreach_wrapper static_ipaddress config_section_close config_section_open "static_routes" config_foreach_wrapper static_routes config_section_close config_foreach_wrapper vrrp_script config_foreach_wrapper vrrp_sync_group config_foreach_wrapper vrrp_instance return 0 } service_triggers() { procd_add_reload_trigger "keepalived" } reload_service() { process_config #SIGHUP is used by keepalived to do init.d reload procd_send_signal keepalived } start_service() { procd_open_instance procd_set_param command /usr/sbin/keepalived procd_append_param command -n # don't daemonize, procd will handle that for us procd_append_param command -f "$KEEPALIVED_CONF" process_config # set auto respawn behavior procd_set_param respawn procd_close_instance }