3 # This is a "library" of sorts for use by the other FRR shell scripts. It
4 # has most of the daemon start/stop logic, but expects the following shell
5 # functions/commands to be provided by the "calling" script:
11 # (coincidentally, these are LSB standard functions.)
13 # Sourcing this file in a shell script will load FRR config variables but
14 # not perform any action. Note there is an "exit 1" if the main config
15 # file does not exist.
17 # This script should be installed in @CFG_SBIN@/frrcommon.sh
19 # FRR_PATHSPACE is passed in from watchfrr
20 suffix
="${FRR_PATHSPACE:+/${FRR_PATHSPACE}}"
21 nsopt
="${FRR_PATHSPACE:+-N ${FRR_PATHSPACE}}"
23 PATH
=/bin
:/usr
/bin
:/sbin
:/usr
/sbin
24 D_PATH
="@CFG_SBIN@" # /usr/lib/frr
25 C_PATH
="@CFG_SYSCONF@${suffix}" # /etc/frr
26 V_PATH
="@CFG_STATE@${suffix}" # /var/run/frr
27 VTYSH
="@vtysh_bin@" # /usr/bin/vtysh
28 FRR_USER
="@enable_user@" # frr
29 FRR_GROUP
="@enable_group@" # frr
30 FRR_VTY_GROUP
="@enable_vty_group@" # frrvty
31 FRR_CONFIG_MODE
="@enable_configfile_mask@" # 0600
32 FRR_DEFAULT_PROFILE
="@DFLT_NAME@" # traditional / datacenter
34 # ORDER MATTERS FOR $DAEMONS!
36 # - watchfrr does NOT belong in this list
38 DAEMONS
="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd pim6d ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
39 RELOAD_SCRIPT
="$D_PATH/frr-reload.py"
46 [ "${EUID:-$(id -u)}" -eq 0 ] ||
{
47 log_failure_msg
"Only users having EUID=0 can start/stop daemons"
53 [ -n "$watchfrr_debug" ] ||
return 0
55 printf '%s %s(%s):' "$(date +%Y-%m-%dT%H:%M:%S.%N)" "$0" $$
>&2
56 # this is to show how arguments are split regarding whitespace & co.
57 # (e.g. for use with `debug "message" "$@"`)
58 while [ $# -gt 0 ]; do
59 printf ' "%s"' "$1" >&2
66 [ -n "$FRR_USER" ] && chown
"$FRR_USER" "$1"
67 [ -n "$FRR_GROUP" ] && chgrp
"$FRR_GROUP" "$1"
68 [ -n "$FRR_CONFIG_MODE" ] && chmod "$FRR_CONFIG_MODE" "$1"
75 [ "$1" = "watchfrr" ] && return 0
76 if [ ! -r "$C_PATH/frr.conf" ]; then
77 log_warning_msg
"$C_PATH/frr.conf does not exist; skipping config apply"
81 cmd
="$VTYSH $nsopt -b"
82 [ -n "$1" ] && cmd
="${cmd} -d $1"
84 log_success_msg
"Sending config with '$cmd'"
89 # note this sets global variables ($dmninst, $daemon, $inst)
91 daemon
="${dmninst%-*}"
93 [ "$daemon" != "$dmninst" ] && inst
="${dmninst#*-}"
97 # note $1 and $2 specify names for global variables to be set
98 local enabled disabled evar dvar
104 for daemon
in $DAEMONS; do
106 eval inst
=\$
${daemon}_instances
107 [ "$daemon" = zebra
-o "$daemon" = staticd
] && cfg
=yes
108 if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then
109 if ! daemon_prep
"$daemon" "$inst"; then
112 debug
"$daemon enabled"
114 if [ -n "$inst" ]; then
115 debug
"$daemon multi-instance $inst"
119 enabled
="$enabled $daemon-$i"
123 enabled
="$enabled $daemon"
126 debug
"$daemon disabled"
127 disabled
="$disabled $daemon"
131 enabled
="${enabled# }"
132 disabled
="${disabled# }"
133 [ -z "$evar" ] && echo "$enabled"
134 [ -n "$evar" ] && eval $evar="\"$enabled\""
135 [ -n "$dvar" ] && eval $dvar="\"$disabled\""
139 # individual daemon management
143 local daemon inst cfg
146 [ "$daemon" = "watchfrr" ] && return 0
147 [ -x "$D_PATH/$daemon" ] ||
{
148 log_failure_msg
"cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed"
151 [ -r "$C_PATH/frr.conf" ] && return 0
153 cfg
="$C_PATH/$daemon${inst:+-$inst}.conf"
154 if [ ! -r "$cfg" ]; then
162 local dmninst daemon inst args instopt wrap bin
164 is_user_root ||
exit 1
167 [ "$1" = "--all" ] && { all
=true
; shift; }
171 [ "$MAX_FDS" != "" ] && ulimit -n "$MAX_FDS" > /dev
/null
2> /dev
/null
172 daemon_prep
"$daemon" "$inst" ||
return 1
173 if test ! -d "$V_PATH"; then
178 eval wrap
="\$${daemon}_wrap"
179 bin
="$D_PATH/$daemon"
180 instopt
="${inst:+-n $inst}"
181 eval args
="\$${daemon}_options"
183 cmd
="$all_wrap $wrap $bin $nsopt -d $frr_global_options $instopt $args"
184 log_success_msg
"Starting $daemon with command: '$cmd'"
186 log_success_msg
"Started $dmninst"
188 debug
"Skipping startup of vtysh until all have started"
193 log_failure_msg
"Failed to start $dmninst!"
198 local dmninst daemon inst pidfile vtyfile pid cnt fail
201 is_user_root ||
exit 1
204 [ "$2" = "--reallyall" ] && all
=true
206 pidfile
="$V_PATH/$daemon${inst:+-$inst}.pid"
207 vtyfile
="$V_PATH/$daemon${inst:+-$inst}.vty"
209 [ -r "$pidfile" ] || fail
="pid file not found"
210 $all && [ -n "$fail" ] && return 0
211 [ -z "$fail" ] && pid
="$(cat "$pidfile")"
212 [ -z "$fail" -a -z "$pid" ] && fail
="pid file is empty"
213 [ -n "$fail" ] ||
kill -0 "$pid" 2>/dev
/null || fail
="pid $pid not running"
215 if [ -n "$fail" ] && [ "$2" != "--quiet" ]; then
216 log_failure_msg
"Cannot stop $dmninst: $fail"
223 while kill -0 "$pid" 2>/dev
/null
; do
225 [ $
(( cnt
-= 1 )) -gt 0 ] ||
break
227 if kill -0 "$pid" 2>/dev
/null
; then
228 log_failure_msg
"Failed to stop $dmninst, pid $pid still running"
232 log_success_msg
"Stopped $dmninst"
239 local dmninst daemon inst pidfile pid fail
242 pidfile
="$V_PATH/$daemon${inst:+-$inst}.pid"
244 [ -r "$pidfile" ] ||
return 3
245 pid
="$(cat "$pidfile")"
246 [ -z "$pid" ] && return 1
247 kill -0 "$pid" 2>/dev
/null ||
return 1
254 if [ "$rv" -eq 0 ]; then
255 log_success_msg
"Status of $1: running"
257 log_failure_msg
"Status of $1: FAILED"
263 # all-daemon commands
268 for dmninst
in $daemons; do
269 daemon_start
--all "$dmninst"
275 local pids reversed need_zebra
277 daemon_list enabled_daemons disabled_daemons
278 [ "$1" = "--reallyall" ] && enabled_daemons
="$enabled_daemons $disabled_daemons"
281 for dmninst
in $enabled_daemons; do
282 reversed
="$dmninst $reversed"
285 # Stop zebra last, after trying to stop the other daemons
286 for dmninst
in $reversed; do
287 if [ "$dmninst" = "zebra" ]; then
292 daemon_stop
"$dmninst" "$1" &
299 if [ -n "$need_zebra" ]; then
309 for dmninst
in $daemons; do
310 print_status
"$dmninst" || fail
=1
321 [ -r "$oldcfg" ] ||
return 0
322 [ -s "$oldcfg" ] ||
return 0
323 grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev
/null ||
return 0
325 log_warning_msg
"Reading deprecated $oldcfg. Please move its settings to $C_PATH/daemons and remove it."
327 # save off settings from daemons for the OR below
328 for dmn
in $DAEMONS; do eval "_new_$dmn=\${$dmn:-no}"; done
332 # OR together the daemon enabling options between config files
333 for dmn
in $DAEMONS; do eval "test \$_new_$dmn != no && $dmn=\$_new_$dmn; unset _new_$dmn"; done
336 [ -r "$C_PATH/daemons" ] ||
{
337 log_failure_msg
"cannot run $@: $C_PATH/daemons does not exist"
342 if [ -z "$FRR_PATHSPACE" ]; then
343 load_old_config
"$C_PATH/daemons.conf"
344 load_old_config
"/etc/default/frr"
345 load_old_config
"/etc/sysconfig/frr"
348 if { declare -p watchfrr_options
2>/dev
/null || true
; } |
grep -q '^declare \-a'; then
349 log_warning_msg
"watchfrr_options contains a bash array value." \
350 "The configured value is intentionally ignored since it is likely wrong." \
351 "Please remove or fix the setting."
352 unset watchfrr_options
355 if test -z "$frr_profile"; then
356 # try to autodetect config profile
357 if test -d /etc
/cumulus
; then
358 frr_profile
=datacenter
359 # elif test ...; then
360 # -- add your distro/system here
361 elif test -n "$FRR_DEFAULT_PROFILE"; then
362 frr_profile
="$FRR_DEFAULT_PROFILE"
365 test -n "$frr_profile" && frr_global_options
="$frr_global_options -F $frr_profile"
368 # other defaults and dispatch
374 debug
"frrcommon_main" "$@"
379 if [ "$1" = "all" ] ||
[ -z "$1" ]; then
391 start
) daemon_start
"$@";;
392 stop
) daemon_stop
"$@";;