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