mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 02:46:26 +00:00

This separates the init script used for the system (and called in the systemd unit file) from the script that watchfrr uses to control daemons. Mixing these two caused the entire thing to become a rather huge spaghetti mess. Note that there is a behaviour change in that the new script always starts zebra regardless of zebra_enable. Side changes: - Ubuntu 12.04 removed from backports since it doesn't work anyway - zebra is always started regardless of zebra_enable. To disable FRR, the entire init script should be disabled through policy. - no-watchfrr operation is no longer supported by the scripts in the Debian packages. (This is intentional.) Signed-off-by: David Lamparter <equinox@diac24.net>
318 lines
6.6 KiB
Bash
318 lines
6.6 KiB
Bash
#!/bin/sh
|
|
#
|
|
# This is a "library" of sorts for use by the other FRR shell scripts. It
|
|
# has most of the daemon start/stop logic, but expects the following shell
|
|
# functions/commands to be provided by the "calling" script:
|
|
#
|
|
# log_success_msg
|
|
# log_warning_msg
|
|
# log_failure_msg
|
|
#
|
|
# (coincidentally, these are LSB standard functions.)
|
|
#
|
|
# Sourcing this file in a shell script will load FRR config variables but
|
|
# not perform any action. Note there is an "exit 1" if the main config
|
|
# file does not exist.
|
|
#
|
|
# This script should be installed in @CFG_SBIN@/frrcommon.sh
|
|
|
|
PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
|
D_PATH="@CFG_SBIN@" # /usr/lib/frr
|
|
C_PATH="@CFG_SYSCONF@" # /etc/frr
|
|
V_PATH="@CFG_STATE@" # /var/run/frr
|
|
VTYSH="@vtysh_bin@" # /usr/bin/vtysh
|
|
FRR_USER="@enable_user@" # frr
|
|
FRR_GROUP="@enable_group@" # frr
|
|
FRR_VTY_GROUP="@enable_vty_group@" # frrvty
|
|
|
|
# ORDER MATTERS FOR $DAEMONS!
|
|
# - keep zebra first
|
|
# - watchfrr does NOT belong in this list
|
|
|
|
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd"
|
|
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
|
|
|
|
#
|
|
# general helpers
|
|
#
|
|
|
|
debug() {
|
|
[ -n "$watchfrr_debug" ] || return 0
|
|
|
|
printf '%s %s(%s):' "`date +%Y-%m-%dT%H:%M:%S.%N`" "$0" $$ >&2
|
|
# this is to show how arguments are split regarding whitespace & co.
|
|
# (e.g. for use with `debug "message" "$@"`)
|
|
while [ $# -gt 0 ]; do
|
|
printf ' "%s"' "$1" >&2
|
|
shift
|
|
done
|
|
printf '\n' >&2
|
|
}
|
|
|
|
chownfrr() {
|
|
[ -n "$FRR_USER" ] && chown "$FRR_USER" "$1"
|
|
[ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1"
|
|
}
|
|
|
|
vtysh_b () {
|
|
[ "$1" = "watchfrr" ] && return 0
|
|
[ -r "$C_PATH/frr.conf" ] || return 0
|
|
if [ -n "$1" ]; then
|
|
"$VTYSH" -b -n -d "$1"
|
|
else
|
|
"$VTYSH" -b -n
|
|
fi
|
|
}
|
|
|
|
daemon_inst() {
|
|
# note this sets global variables ($dmninst, $daemon, $inst)
|
|
dmninst="$1"
|
|
daemon="${dmninst%:*}"
|
|
inst=""
|
|
[ "$daemon" != "$dmninst" ] && inst="${dmninst#*:}"
|
|
}
|
|
|
|
daemon_list() {
|
|
# note $1 and $2 specify names for global variables to be set
|
|
local enabled disabled evar dvar
|
|
enabled=""
|
|
disabled=""
|
|
evar="$1"
|
|
dvar="$2"
|
|
|
|
for daemon in $DAEMONS; do
|
|
eval cfg=\$$daemon
|
|
eval inst=\$${daemon}_instances
|
|
[ "$daemon" = zebra ] && cfg=yes
|
|
if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then
|
|
debug "$daemon enabled"
|
|
enabled="$enabled $daemon"
|
|
if [ -n "$inst" ]; then
|
|
debug "$daemon multi-instance $inst"
|
|
for i in $inst; do
|
|
enabled="$enabled $daemon:$inst"
|
|
done
|
|
fi
|
|
else
|
|
debug "$daemon disabled"
|
|
disabled="$disabled $daemon"
|
|
fi
|
|
done
|
|
|
|
enabled="${enabled# }"
|
|
disabled="${disabled# }"
|
|
[ -z "$evar" ] && echo "$enabled"
|
|
[ -n "$evar" ] && eval $evar="\"$enabled\""
|
|
[ -n "$dvar" ] && eval $dvar="\"$disabled\""
|
|
}
|
|
|
|
#
|
|
# individual daemon management
|
|
#
|
|
|
|
daemon_prep() {
|
|
local daemon inst cfg
|
|
daemon="$1"
|
|
inst="$2"
|
|
[ "$daemon" = "watchfrr" ] && return 0
|
|
[ -x "$D_PATH/$daemon" ] || {
|
|
log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed\n"
|
|
return 1
|
|
}
|
|
[ -r "$C_PATH/frr.conf" ] && return 0
|
|
|
|
cfg="$C_PATH/$daemon${inst:+-$inst}.conf"
|
|
if [ ! -r "$cfg" ]; then
|
|
touch "$cfg"
|
|
chownfrr "$cfg"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
daemon_start() {
|
|
local dmninst daemon inst args instopt wrap bin
|
|
daemon_inst "$1"
|
|
|
|
ulimit -n $MAX_FDS > /dev/null 2> /dev/null
|
|
daemon_prep "$daemon" "$inst" || return 1
|
|
|
|
eval wrap="\$${daemon}_wrap"
|
|
bin="$D_PATH/$daemon"
|
|
instopt="${inst:+-n $inst}"
|
|
eval args="\$${daemon}_options"
|
|
|
|
if eval "$all_wrap $wrap $bin -d $instopt $args"; then
|
|
log_success_msg "Started $dmninst"
|
|
vtysh_b "$daemon"
|
|
else
|
|
log_failure_msg "Failed to start $dmninst!"
|
|
fi
|
|
}
|
|
|
|
daemon_stop() {
|
|
local dmninst daemon inst pidfile vtyfile pid cnt fail
|
|
daemon_inst "$1"
|
|
|
|
pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
|
|
vtyfile="$V_PATH/$daemon${inst:+-$inst}.vty"
|
|
|
|
[ -r "$pidfile" ] || fail="pid file not found"
|
|
[ -z "$fail" ] && pid="`cat \"$pidfile\"`"
|
|
[ -z "$fail" -a -z "$pid" ] && fail="pid file is empty"
|
|
[ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running"
|
|
|
|
if [ -n "$fail" ]; then
|
|
log_failure_msg "Cannot stop $dmninst: $fail"
|
|
return 1
|
|
fi
|
|
|
|
debug "kill -2 $pid"
|
|
kill -2 "$pid"
|
|
cnt=1200
|
|
while kill -0 "$pid" 2>/dev/null; do
|
|
sleep .1
|
|
[ $(( cnt -= 1 )) -gt 0 ] || break
|
|
done
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
log_failure_msg "Failed to stop $dmninst, pid $pid still running"
|
|
still_running=1
|
|
return 1
|
|
else
|
|
log_success_msg "Stopped $dmninst"
|
|
rm -f "$pidfile"
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
daemon_status() {
|
|
local dmninst daemon inst pidfile pid fail
|
|
daemon_inst "$1"
|
|
|
|
pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
|
|
|
|
[ -r "$pidfile" ] || return 3
|
|
pid="`cat \"$pidfile\"`"
|
|
[ -z "$pid" ] && return 1
|
|
kill -0 "$pid" 2>/dev/null || return 1
|
|
return 0
|
|
}
|
|
|
|
print_status() {
|
|
daemon_status "$1"
|
|
rv=$?
|
|
if [ "$rv" -eq 0 ]; then
|
|
log_success_msg "Status of $1: running"
|
|
else
|
|
log_failure_msg "Status of $1: FAILED"
|
|
fi
|
|
return $rv
|
|
}
|
|
|
|
#
|
|
# all-daemon commands
|
|
#
|
|
|
|
all_start() {
|
|
daemon_list daemons
|
|
for dmninst in $daemons; do
|
|
daemon_start "$dmninst"
|
|
done
|
|
}
|
|
|
|
all_stop() {
|
|
local pids reversed
|
|
|
|
daemon_list daemons disabled
|
|
[ "$1" = "--reallyall" ] && daemons="$daemons $disabled"
|
|
|
|
reversed=""
|
|
for dmninst in $daemons; do
|
|
reversed="$dmninst $reversed"
|
|
done
|
|
|
|
for dmninst in $reversed; do
|
|
daemon_stop "$dmninst" &
|
|
pids="$pids $!"
|
|
done
|
|
for pid in $pids; do
|
|
wait $pid
|
|
done
|
|
}
|
|
|
|
all_status() {
|
|
local fail
|
|
|
|
daemon_list daemons
|
|
fail=0
|
|
for dmninst in $daemons; do
|
|
print_status "$dmninst" || fail=1
|
|
done
|
|
return $fail
|
|
}
|
|
|
|
#
|
|
# config sourcing
|
|
#
|
|
|
|
load_old_config() {
|
|
oldcfg="$1"
|
|
[ -r "$oldcfg" ] || return 0
|
|
[ -s "$oldcfg" ] || return 0
|
|
grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev/null || return 0
|
|
|
|
log_warning_msg "Reading deprecated $oldcfg. Please move its settings to $C_PATH/daemons and remove it."
|
|
|
|
# save off settings from daemons for the OR below
|
|
for dmn in $DAEMONS; do eval "_new_$dmn=\${$dmn:-no}"; done
|
|
|
|
. "$oldcfg"
|
|
|
|
# OR together the daemon enabling options between config files
|
|
for dmn in $DAEMONS; do eval "test \$_new_$dmn != no && $dmn=\$_new_$dmn; unset _new_$dmn"; done
|
|
}
|
|
|
|
[ -r "$C_PATH/daemons" ] || {
|
|
log_failure_msg "cannot run $@: $C_PATH/daemons does not exist\n"
|
|
exit 1
|
|
}
|
|
. "$C_PATH/daemons"
|
|
|
|
load_old_config "$C_PATH/daemons.conf"
|
|
load_old_config "/etc/default/frr"
|
|
load_old_config "/etc/sysconfig/frr"
|
|
|
|
#
|
|
# other defaults and dispatch
|
|
#
|
|
|
|
frrcommon_main() {
|
|
local cmd
|
|
|
|
debug "frrcommon_main" "$@"
|
|
|
|
cmd="$1"
|
|
shift
|
|
|
|
if [ "$1" = "all" -o -z "$1" ]; then
|
|
case "$cmd" in
|
|
start) all_start;;
|
|
stop) all_stop;;
|
|
restart)
|
|
all_stop
|
|
all_start
|
|
;;
|
|
*) $cmd "$@";;
|
|
esac
|
|
else
|
|
case "$cmd" in
|
|
start) daemon_start "$@";;
|
|
stop) daemon_stop "$@";;
|
|
restart)
|
|
daemon_stop "$@"
|
|
daemon_start "$@"
|
|
;;
|
|
*) $cmd "$@";;
|
|
esac
|
|
fi
|
|
}
|