#!/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 or device exit
|
|
[ -z "$address" -o -z "$device" ] && return 0
|
|
|
|
# Add IP address/netmask and device
|
|
printf "$indent$address dev $device" >> $KEEPALIVED_CONF
|
|
# Add scope
|
|
[ -n "$scope" ] && printf " scope $scope" >> $KEEPALIVED_CONF
|
|
|
|
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 use_vmac 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
|
|
|
|
print_notify "INSTANCE" "$name" notify_backup notify_master \
|
|
notify_fault notify_stop notify
|
|
|
|
# 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\n" > $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_running() {
|
|
pgrep -x /usr/sbin/keepalived &> /dev/null
|
|
}
|
|
|
|
conf_md5() {
|
|
echo "$(md5sum $KEEPALIVED_CONF | awk '{print $1}')"
|
|
}
|
|
|
|
reload_service() {
|
|
local cur_md5="$(conf_md5)"
|
|
running && {
|
|
process_config
|
|
|
|
# Return without performing the reload if config
|
|
# file md5sum has not changed
|
|
local new_md5="$(conf_md5)"
|
|
[ "$new_md5" == "$cur_md5" ] && return 0;
|
|
|
|
# SIGHUP is used by keepalived to do init.d reload
|
|
# Get the oldest process (assumption is that it's the parent process)
|
|
PID=$(pgrep -o /usr/sbin/keepalived)
|
|
kill -SIGHUP $PID
|
|
return 0
|
|
}
|
|
return 1
|
|
}
|
|
|
|
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
|
|
}
|
|
|