]> git.proxmox.com Git - mirror_frr.git/blob - tools/frrcommon.sh.in
doc: indicate non-support for dynamic pbr maps
[mirror_frr.git] / tools / frrcommon.sh.in
1 #!/bin/bash
2 #
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:
6 #
7 # log_success_msg
8 # log_warning_msg
9 # log_failure_msg
10 #
11 # (coincidentally, these are LSB standard functions.)
12 #
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.
16 #
17 # This script should be installed in @CFG_SBIN@/frrcommon.sh
18
19 PATH=/bin:/usr/bin:/sbin:/usr/sbin
20 D_PATH="@CFG_SBIN@" # /usr/lib/frr
21 C_PATH="@CFG_SYSCONF@" # /etc/frr
22 V_PATH="@CFG_STATE@" # /var/run/frr
23 VTYSH="@vtysh_bin@" # /usr/bin/vtysh
24 FRR_USER="@enable_user@" # frr
25 FRR_GROUP="@enable_group@" # frr
26 FRR_VTY_GROUP="@enable_vty_group@" # frrvty
27 FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter
28
29 # ORDER MATTERS FOR $DAEMONS!
30 # - keep zebra first
31 # - watchfrr does NOT belong in this list
32
33 DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd"
34 RELOAD_SCRIPT="$D_PATH/frr-reload.py"
35
36 #
37 # general helpers
38 #
39
40 debug() {
41 [ -n "$watchfrr_debug" ] || return 0
42
43 printf '%s %s(%s):' "`date +%Y-%m-%dT%H:%M:%S.%N`" "$0" $$ >&2
44 # this is to show how arguments are split regarding whitespace & co.
45 # (e.g. for use with `debug "message" "$@"`)
46 while [ $# -gt 0 ]; do
47 printf ' "%s"' "$1" >&2
48 shift
49 done
50 printf '\n' >&2
51 }
52
53 chownfrr() {
54 [ -n "$FRR_USER" ] && chown "$FRR_USER" "$1"
55 [ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1"
56 }
57
58 vtysh_b () {
59 [ "$1" = "watchfrr" ] && return 0
60 [ -r "$C_PATH/frr.conf" ] || return 0
61 if [ -n "$1" ]; then
62 "$VTYSH" -b -n -d "$1"
63 else
64 "$VTYSH" -b -n
65 fi
66 }
67
68 daemon_inst() {
69 # note this sets global variables ($dmninst, $daemon, $inst)
70 dmninst="$1"
71 daemon="${dmninst%-*}"
72 inst=""
73 [ "$daemon" != "$dmninst" ] && inst="${dmninst#*-}"
74 }
75
76 daemon_list() {
77 # note $1 and $2 specify names for global variables to be set
78 local enabled disabled evar dvar
79 enabled=""
80 disabled=""
81 evar="$1"
82 dvar="$2"
83
84 for daemon in $DAEMONS; do
85 eval cfg=\$$daemon
86 eval inst=\$${daemon}_instances
87 [ "$daemon" = zebra -o "$daemon" = staticd ] && cfg=yes
88 if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then
89 if ! daemon_prep "$daemon" "$inst"; then
90 continue
91 fi
92 debug "$daemon enabled"
93 enabled="$enabled $daemon"
94 if [ -n "$inst" ]; then
95 debug "$daemon multi-instance $inst"
96 oldifs="${IFS}"
97 IFS="${IFS},"
98 for i in $inst; do
99 enabled="$enabled $daemon-$i"
100 done
101 IFS="${oldifs}"
102 fi
103 else
104 debug "$daemon disabled"
105 disabled="$disabled $daemon"
106 fi
107 done
108
109 enabled="${enabled# }"
110 disabled="${disabled# }"
111 [ -z "$evar" ] && echo "$enabled"
112 [ -n "$evar" ] && eval $evar="\"$enabled\""
113 [ -n "$dvar" ] && eval $dvar="\"$disabled\""
114 }
115
116 #
117 # individual daemon management
118 #
119
120 daemon_prep() {
121 local daemon inst cfg
122 daemon="$1"
123 inst="$2"
124 [ "$daemon" = "watchfrr" ] && return 0
125 [ -x "$D_PATH/$daemon" ] || {
126 log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed"
127 return 1
128 }
129 [ -r "$C_PATH/frr.conf" ] && return 0
130
131 cfg="$C_PATH/$daemon${inst:+-$inst}.conf"
132 if [ ! -r "$cfg" ]; then
133 touch "$cfg"
134 chownfrr "$cfg"
135 fi
136 return 0
137 }
138
139 daemon_start() {
140 local dmninst daemon inst args instopt wrap bin
141 daemon_inst "$1"
142
143 ulimit -n $MAX_FDS > /dev/null 2> /dev/null
144 daemon_prep "$daemon" "$inst" || return 1
145 if test ! -d "$V_PATH"; then
146 mkdir -p "$V_PATH"
147 chown frr "$V_PATH"
148 fi
149
150 eval wrap="\$${daemon}_wrap"
151 bin="$D_PATH/$daemon"
152 instopt="${inst:+-n $inst}"
153 eval args="\$${daemon}_options"
154
155 if eval "$all_wrap $wrap $bin -d $frr_global_options $instopt $args"; then
156 log_success_msg "Started $dmninst"
157 vtysh_b "$daemon"
158 else
159 log_failure_msg "Failed to start $dmninst!"
160 fi
161 }
162
163 daemon_stop() {
164 local dmninst daemon inst pidfile vtyfile pid cnt fail
165 daemon_inst "$1"
166
167 pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
168 vtyfile="$V_PATH/$daemon${inst:+-$inst}.vty"
169
170 [ -r "$pidfile" ] || fail="pid file not found"
171 [ -z "$fail" ] && pid="`cat \"$pidfile\"`"
172 [ -z "$fail" -a -z "$pid" ] && fail="pid file is empty"
173 [ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running"
174
175 if [ -n "$fail" ]; then
176 log_failure_msg "Cannot stop $dmninst: $fail"
177 return 1
178 fi
179
180 debug "kill -2 $pid"
181 kill -2 "$pid"
182 cnt=1200
183 while kill -0 "$pid" 2>/dev/null; do
184 sleep .1
185 [ $(( cnt -= 1 )) -gt 0 ] || break
186 done
187 if kill -0 "$pid" 2>/dev/null; then
188 log_failure_msg "Failed to stop $dmninst, pid $pid still running"
189 still_running=1
190 return 1
191 else
192 log_success_msg "Stopped $dmninst"
193 rm -f "$pidfile"
194 return 0
195 fi
196 }
197
198 daemon_status() {
199 local dmninst daemon inst pidfile pid fail
200 daemon_inst "$1"
201
202 pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
203
204 [ -r "$pidfile" ] || return 3
205 pid="`cat \"$pidfile\"`"
206 [ -z "$pid" ] && return 1
207 kill -0 "$pid" 2>/dev/null || return 1
208 return 0
209 }
210
211 print_status() {
212 daemon_status "$1"
213 rv=$?
214 if [ "$rv" -eq 0 ]; then
215 log_success_msg "Status of $1: running"
216 else
217 log_failure_msg "Status of $1: FAILED"
218 fi
219 return $rv
220 }
221
222 #
223 # all-daemon commands
224 #
225
226 all_start() {
227 daemon_list daemons
228 for dmninst in $daemons; do
229 daemon_start "$dmninst"
230 done
231 }
232
233 all_stop() {
234 local pids reversed
235
236 daemon_list daemons disabled
237 [ "$1" = "--reallyall" ] && daemons="$daemons $disabled"
238
239 reversed=""
240 for dmninst in $daemons; do
241 reversed="$dmninst $reversed"
242 done
243
244 for dmninst in $reversed; do
245 daemon_stop "$dmninst" &
246 pids="$pids $!"
247 done
248 for pid in $pids; do
249 wait $pid
250 done
251 }
252
253 all_status() {
254 local fail
255
256 daemon_list daemons
257 fail=0
258 for dmninst in $daemons; do
259 print_status "$dmninst" || fail=1
260 done
261 return $fail
262 }
263
264 #
265 # config sourcing
266 #
267
268 load_old_config() {
269 oldcfg="$1"
270 [ -r "$oldcfg" ] || return 0
271 [ -s "$oldcfg" ] || return 0
272 grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev/null || return 0
273
274 log_warning_msg "Reading deprecated $oldcfg. Please move its settings to $C_PATH/daemons and remove it."
275
276 # save off settings from daemons for the OR below
277 for dmn in $DAEMONS; do eval "_new_$dmn=\${$dmn:-no}"; done
278
279 . "$oldcfg"
280
281 # OR together the daemon enabling options between config files
282 for dmn in $DAEMONS; do eval "test \$_new_$dmn != no && $dmn=\$_new_$dmn; unset _new_$dmn"; done
283 }
284
285 [ -r "$C_PATH/daemons" ] || {
286 log_failure_msg "cannot run $@: $C_PATH/daemons does not exist"
287 exit 1
288 }
289 . "$C_PATH/daemons"
290
291 load_old_config "$C_PATH/daemons.conf"
292 load_old_config "/etc/default/frr"
293 load_old_config "/etc/sysconfig/frr"
294
295 if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then
296 log_warning_msg "watchfrr_options contains a bash array value." \
297 "The configured value is intentionally ignored since it is likely wrong." \
298 "Please remove or fix the setting."
299 unset watchfrr_options
300 fi
301
302 if test -z "$frr_profile"; then
303 # try to autodetect config profile
304 if test -d /etc/cumulus; then
305 frr_profile=datacenter
306 # elif test ...; then
307 # -- add your distro/system here
308 elif test -n "$FRR_DEFAULT_PROFILE"; then
309 frr_profile="$FRR_DEFAULT_PROFILE"
310 fi
311 fi
312 test -n "$frr_profile" && frr_global_options="$frr_global_options -F $frr_profile"
313
314 #
315 # other defaults and dispatch
316 #
317
318 frrcommon_main() {
319 local cmd
320
321 debug "frrcommon_main" "$@"
322
323 cmd="$1"
324 shift
325
326 if [ "$1" = "all" -o -z "$1" ]; then
327 case "$cmd" in
328 start) all_start;;
329 stop) all_stop;;
330 restart)
331 all_stop
332 all_start
333 ;;
334 *) $cmd "$@";;
335 esac
336 else
337 case "$cmd" in
338 start) daemon_start "$@";;
339 stop) daemon_stop "$@";;
340 restart)
341 daemon_stop "$@"
342 daemon_start "$@"
343 ;;
344 *) $cmd "$@";;
345 esac
346 fi
347 }