]> git.proxmox.com Git - mirror_frr.git/blob - tools/frr.in
Merge pull request #3506 from opensourcerouting/6.0-init-fixes
[mirror_frr.git] / tools / frr.in
1 #!/bin/bash
2 #
3 ### BEGIN INIT INFO
4 # Provides: frr
5 # Required-Start: $local_fs $network $remote_fs $syslog
6 # Required-Stop: $local_fs $network $remote_fs $syslog
7 # Default-Start: 2 3 4 5
8 # Default-Stop: 0 1 6
9 # Short-Description: start and stop the Frr routing suite
10 # Description: Frr is a routing suite for IP routing protocols like
11 # BGP, OSPF, RIP and others. This script contols the main
12 # daemon "frr" as well as the individual protocol daemons.
13 ### END INIT INFO
14 #
15
16 PATH=/bin:/usr/bin:/sbin:/usr/sbin
17 D_PATH="@CFG_SBIN@" # /usr/lib/frr
18 C_PATH="@CFG_SYSCONF@" # /etc/frr
19 V_PATH="@CFG_STATE@" # /var/run/frr
20 VTYSH="@vtysh_bin@" # /usr/bin/vtysh
21 FRR_USER="@enable_user@" # frr
22 FRR_GROUP="@enable_group@" # frr
23 FRR_VTY_GROUP="@enable_vty_group@" # frrvty
24
25 # Local Daemon selection may be done by using /etc/frr/daemons.
26 # See /usr/share/doc/frr/README.Debian.gz for further information.
27 # Keep zebra first and do not list watchfrr!
28 DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd"
29 MAX_INSTANCES=5
30 RELOAD_SCRIPT="$D_PATH/frr-reload.py"
31 WATCHFRR_STARTED="$V_PATH/watchfrr.started"
32
33 if [ -e /lib/lsb/init-functions ]; then
34 . /lib/lsb/init-functions
35 fi
36
37 if [ -f $D_PATH/ssd ]; then
38 SSD=$D_PATH/ssd
39 else
40 SSD=`which start-stop-daemon`
41 fi
42
43 # Print the name of the pidfile.
44 pidfile()
45 {
46 echo "$V_PATH/$1.pid"
47 }
48
49 # Print the name of the vtysh.
50 vtyfile()
51 {
52 echo "$V_PATH/$1.vty"
53 }
54
55 chownfrr()
56 {
57 test -n "$FRR_USER" && chown "$FRR_USER" "$1"
58 test -n "$FRR_GROUP" && chgrp "$FRR_GROUP" "$1"
59 }
60
61 # Check if daemon is started by using the pidfile.
62 started()
63 {
64 [ ! -e `pidfile $1` ] && return 3
65 if [ -n "$2" ] && [ "$2" == "log" ]; then
66 status_of_proc -p `pidfile $1` $1 $1 && return 0 || return $?
67 else
68 kill -0 `cat \`pidfile $1\`` 2> /dev/null || return 1
69 return 0
70 fi
71 }
72
73 # Loads the config via vtysh -b if configured to do so.
74 vtysh_b ()
75 {
76 # Rember, that all variables have been incremented by 1 in convert_daemon_prios()
77 if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then
78 $VTYSH -b -n
79 fi
80 }
81
82 # Check if the daemon is activated and if its executable and config files
83 # are in place.
84 # params: daemon name
85 # returns: 0=ok, 1=error
86 check_daemon()
87 {
88 if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then
89 # check for daemon binary
90 if [ ! -x "$D_PATH/$1" ]; then return 1; fi
91 fi
92
93 # If the integrated config file is used the others are not checked.
94 if [ -r "$C_PATH/frr.conf" ]; then
95 return 0
96 fi
97
98 # vtysh_enable has no config file nor binary so skip check.
99 # (Not sure why vtysh_enable is in this list but does not hurt)
100 if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then
101 # check for config file
102 if [ -n "$2" ]; then
103 if [ ! -r "$C_PATH/$1-$2.conf" ]; then
104 touch "$C_PATH/$1-$2.conf"
105 chownfrr "$C_PATH/$1-$2.conf"
106 fi
107 elif [ ! -r "$C_PATH/$1.conf" ]; then
108 touch "$C_PATH/$1.conf"
109 chownfrr "$C_PATH/$1.conf"
110 fi
111 fi
112 return 0
113 }
114
115 # Starts the server if it's not alrady running according to the pid file.
116 # The Frr daemons creates the pidfile when starting.
117 start()
118 {
119 local dmn inst
120 dmn="$1"
121 inst="$2"
122
123 ulimit -n $MAX_FDS
124 if [ "$dmn" = "watchfrr" ]; then
125
126 # We may need to restart watchfrr if new daemons are added and/or
127 # removed
128 if started "$dmn" ; then
129 stop watchfrr
130 else
131 # Echo only once. watchfrr is printed in the stop above
132 echo -n " $dmn"
133 fi
134
135 if [ -e $WATCHFRR_STARTED ] ; then
136 rm $WATCHFRR_STARTED
137 fi
138
139 eval "set - $watchfrr_options"
140 ${SSD} \
141 --start \
142 --pidfile=`pidfile $dmn` \
143 --exec "$D_PATH/$dmn" \
144 -- \
145 "$@"
146 for i in `seq 1 10`;
147 do
148 if [ -e $WATCHFRR_STARTED ] ; then
149 break
150 else
151 sleep 1
152 fi
153 done
154 elif [ -n "$inst" ]; then
155 echo -n " $dmn-$inst"
156 if ! check_daemon $dmn $inst ; then
157 echo -n " (binary does not exist)"
158 return;
159 fi
160
161 ${SSD} \
162 --start \
163 --pidfile=`pidfile $dmn-$inst` \
164 --exec "$D_PATH/$dmn" \
165 -- \
166 `eval echo "$""$dmn""_options"` -n "$inst"
167 else
168 echo -n " $dmn"
169 if ! check_daemon $dmn; then
170 echo -n " (binary does not exist)"
171 return;
172 fi
173
174 if [ "$valgrind_enable" = "yes" ]; then
175 ${SSD} \
176 --start \
177 --pidfile=`pidfile $dmn` \
178 --exec "$valgrind" \
179 -- --trace-children=no --leak-check=full --log-file=/var/log/frr/$dmn-valgrind.log $D_PATH/$dmn \
180 `eval echo "$""$dmn""_options"`
181 else
182 ${SSD} \
183 --start \
184 --pidfile=`pidfile $dmn` \
185 --exec "$D_PATH/$dmn" \
186 -- \
187 `eval echo "$""$dmn""_options"`
188 fi
189 fi
190
191 # Start the staticd automatically
192 if [ "$dmn" = "zebra" ]; then
193 echo -n "starting staticd since zebra is running"
194 if ! check_daemon staticd ; then
195 echo -n " (binary does not exist)"
196 return;
197 fi
198
199 ${SSD} \
200 --start \
201 --pidfile=`pidfile staticd` \
202 --exec "$D_PATH/staticd" \
203 -- \
204 `eval echo "$"staticd"_options"`
205 fi
206 }
207
208 # Stop the daemon given in the parameter, printing its name to the terminal.
209 stop()
210 {
211 local inst
212
213 if [ -n "$2" ]; then
214 inst="$1-$2"
215 else
216 inst="$1"
217 fi
218
219 if ! started "$inst" ; then
220 echo -n " ($inst)"
221 return 0
222 else
223 PIDFILE=`pidfile $inst`
224 PID=`cat $PIDFILE 2>/dev/null`
225 kill -2 $PID 2>/dev/null
226 #
227 # Now we have to wait until $DAEMON has _really_ stopped.
228 #
229 if test -n "$PID" && kill -0 $PID 2>/dev/null; then
230 echo -n " (waiting) ."
231 cnt=0
232 while kill -0 $PID 2>/dev/null; do
233 cnt=`expr $cnt + 1`
234 if [ $cnt -gt 60 ]; then
235 # Waited 120 secs now, fail.
236 echo -n "Failed.. "
237 break
238 fi
239 sleep 2
240 echo -n "."
241 done
242 fi
243 echo -n " $inst"
244 rm -f `pidfile $inst`
245 rm -f `vtyfile $inst`
246
247 if [ "$1" = "zebra" ]; then
248 echo -n "Stopping staticd since zebra is running"
249 stop staticd
250 fi
251 fi
252 }
253
254 # Converts values from /etc/frr/daemons to all-numeric values.
255 convert_daemon_prios()
256 {
257 for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do
258 # First, assign the value set by the user to $value
259 eval value=\${${name}:0:3}
260
261 # Daemon not activated or entry missing?
262 if [ "$value" = "no" -o "$value" = "" ]; then value=0; fi
263
264 # These strings parsed for backwards compatibility.
265 if [ "$value" = "yes" -o "$value" = "true" ]; then
266 value=1;
267 fi
268
269 # Zebra is threatened special. It must be between 0=off and the first
270 # user assigned value "1" so we increase all other enabled daemons' values.
271 if [ "$name" != "zebra" -a "$value" -gt 0 ]; then value=`expr "$value" + 1`; fi
272
273 # If e.g. name is zebra then we set "zebra=yes".
274 eval $name=$value
275 done
276 }
277
278 # Starts watchfrr for all wanted daemons.
279 start_watchfrr()
280 {
281 local daemon_name
282 local daemon_prio
283 local found_one
284 local daemon_inst
285
286 # Start the monitor daemon only if desired.
287 if [ 0 -eq "$watchfrr_enable" ]; then
288 return
289 fi
290
291 # Check variable type
292 if declare -p watchfrr_options | grep -q '^declare \-a'; then
293 # old array support
294 watchfrr_options="${watchfrr_options[@]}"
295 fi
296
297 # Which daemons have been started?
298 found_one=0
299 for daemon_name in $DAEMONS; do
300 eval daemon_prio=\$$daemon_name
301 if [ "$daemon_prio" -gt 0 ]; then
302 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
303 if [ -n "$daemon_inst" ]; then
304 for inst in ${daemon_inst}; do
305 eval "inst_disable=\${${daemon_name}_${inst}}"
306 if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then
307 if check_daemon $daemon_name $inst; then
308 watchfrr_options="$watchfrr_options ${daemon_name}-${inst}"
309 fi
310 fi
311 done
312 else
313 if check_daemon $daemon_name; then
314 watchfrr_options="$watchfrr_options $daemon_name"
315 fi
316 fi
317 found_one=1
318 fi
319 done
320
321 # Start if at least one daemon is activated.
322 if [ $found_one -eq 1 ]; then
323 echo -n "Starting Frr monitor daemon:"
324 start watchfrr
325 echo "."
326 fi
327 }
328
329 # Stopps watchfrr.
330 stop_watchfrr()
331 {
332 echo -n "Stopping Frr monitor daemon:"
333 stop watchfrr
334 echo "."
335 }
336
337 # Stops all daemons that have a lower level of priority than the given.
338 # (technically if daemon_prio >= wanted_prio)
339 stop_prio()
340 {
341 local wanted_prio
342 local daemon_prio
343 local daemon_list
344 local daemon_inst
345 local inst
346
347 if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
348 daemon=${BASH_REMATCH[1]}
349 inst=${BASH_REMATCH[2]}
350 else
351 daemon="$2"
352 fi
353
354 wanted_prio=$1
355 daemon_list=${daemon:-$DAEMONS}
356
357 echo -n "Stopping Frr daemons (prio:$wanted_prio):"
358
359 for prio_i in `seq 10 -1 $wanted_prio`; do
360 for daemon_name in $daemon_list; do
361 eval daemon_prio=\${${daemon_name}:0:3}
362 daemon_inst=""
363 if [ $daemon_prio -eq $prio_i ]; then
364 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
365 if [ -n "$daemon_inst" ]; then
366 for i in ${daemon_inst}; do
367 if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
368 stop "$daemon_name" "$inst"
369 elif [ x"$inst" == x ]; then
370 stop "$daemon_name" "$i"
371 fi
372 done
373 else
374 stop "$daemon_name"
375 fi
376 fi
377 done
378 done
379
380 echo "."
381 if [ -z "$inst" ]; then
382 # Now stop other daemons that're prowling, coz the daemons file changed
383 echo -n "Stopping other frr daemons"
384 if [ -n "$daemon" ]; then
385 eval "file_list_suffix="$V_PATH"/"$daemon*""
386 else
387 eval "file_list_suffix="$V_PATH/*""
388 fi
389 for pidfile in $file_list_suffix.pid; do
390 PID=`cat $pidfile 2>/dev/null`
391 ${SSD} --stop --quiet --oknodo --pidfile "$pidfile"
392 echo -n "."
393 rm -rf "$pidfile"
394 done
395 echo "."
396
397 echo -n "Removing remaining .vty files"
398 for vtyfile in $file_list_suffix.vty; do
399 rm -rf "$vtyfile"
400 done
401 echo "."
402 fi
403 }
404
405 # Starts all daemons that have a higher level of priority than the given.
406 # (technically if daemon_prio <= wanted_prio)
407 start_prio()
408 {
409 local wanted_prio
410 local daemon_prio
411 local daemon_list
412 local daemon_name
413 local daemon_inst
414 local inst
415
416 if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
417 daemon=${BASH_REMATCH[1]}
418 inst=${BASH_REMATCH[2]}
419 else
420 daemon="$2"
421 fi
422
423 wanted_prio=$1
424 daemon_list=${daemon:-$DAEMONS}
425
426 echo -n "Starting Frr daemons (prio:$wanted_prio):"
427
428 for prio_i in `seq 1 $wanted_prio`; do
429 for daemon_name in $daemon_list; do
430 eval daemon_prio=\$${daemon_name}
431 daemon_inst=""
432 if [ $daemon_prio -eq $prio_i ]; then
433 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
434 if [ -n "$daemon_inst" ]; then
435 if [ `echo "$daemon_inst" | wc -w` -gt ${MAX_INSTANCES} ]; then
436 echo "Max instances supported is ${MAX_INSTANCES}. Aborting"
437 exit 1
438 fi
439 # Check if we're starting again by switching from single instance
440 # to MI version
441 if started "$daemon_name"; then
442 PIDFILE=`pidfile $daemon_name`
443 ${SSD} \
444 --stop --quiet --oknodo \
445 --pidfile "$PIDFILE" \
446 --exec "$D_PATH/$daemon_name"
447
448 rm -f `pidfile $1`
449 rm -f `vtyfile $1`
450 fi
451
452 for i in ${daemon_inst}; do
453 if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
454 start "$daemon_name" "$inst"
455 elif [ x"$inst" == x ]; then
456 start "$daemon_name" "$i"
457 fi
458 done
459 else
460 # Check if we're starting again by switching from
461 # single instance to MI version
462 eval "file_list_suffix="$V_PATH"/"$daemon_name-*""
463 for pidfile in $file_list_suffix.pid; do
464 ${SSD} --stop --quiet --oknodo --pidfile "$pidfile"
465 echo -n "."
466 rm -rf "$pidfile"
467 done
468 for vtyfile in $file_list_suffix.vty; do
469 rm -rf "$vtyfile"
470 done
471
472 start "$daemon_name"
473 fi
474 fi
475 done
476 done
477 echo "."
478 }
479
480 check_status()
481 {
482 local daemon_name
483 local daemon_prio
484 local daemon_inst
485 local failed_status=0
486
487 if [ -n "$1" ] && [[ "$1" =~ (.*)-(.*) ]]; then
488 daemon=${BASH_REMATCH[1]}
489 inst=${BASH_REMATCH[2]}
490 else
491 daemon="$1"
492 fi
493
494 daemon_list=${daemon:-$DAEMONS}
495
496 # Which daemons have been started?
497 for daemon_name in $daemon_list; do
498 eval daemon_prio=\$$daemon_name
499 if [ "$daemon_prio" -gt 0 ]; then
500 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
501 if [ -n "$daemon_inst" ]; then
502 for i in ${daemon_inst}; do
503 if [ -n "$inst" -a "$inst" = "$i" ]; then
504 started "$1" "log" || failed_status=$?
505 elif [ -z "$inst" ]; then
506 started "$daemon_name-$i" "log" || failed_status=$?
507 fi
508 done
509 else
510 started "$daemon_name" "log" || failed_status=$?
511 fi
512 fi
513 done
514
515 # All daemons that need to have been started are up and running
516 return $failed_status
517 }
518
519 #########################################################
520 # Main program #
521 #########################################################
522
523 # Config broken but script must exit silently.
524 [ ! -r "$C_PATH/daemons" ] && exit 0
525
526 # Load configuration
527 . "$C_PATH/daemons"
528 . "$C_PATH/daemons.conf"
529
530 # Read configuration variable file if it is present
531 [ -r /etc/default/frr ] && . /etc/default/frr
532
533 MAX_INSTANCES=${MAX_INSTANCES:=5}
534
535 # Set priority of un-startable daemons to 'no' and substitute 'yes' to '0'
536 convert_daemon_prios
537
538 if [ ! -d $V_PATH ]; then
539 echo "Creating $V_PATH"
540 mkdir -p $V_PATH
541 chownfrr $V_PATH
542 chmod 755 /$V_PATH
543 fi
544
545 if [ -n "$3" ] && [ "$3" != "all" ]; then
546 dmn="$2"-"$3"
547 elif [ -n "$2" ] && [ "$2" != "all" ]; then
548 dmn="$2"
549 fi
550
551 case "$1" in
552 start)
553 # Try to load this necessary (at least for 2.6) module.
554 if [ -d /lib/modules/`uname -r` ] ; then
555 echo "Loading capability module if not yet done."
556 set +e; LC_ALL=C modprobe -a capability 2>&1 | egrep -v "(not found|Can't locate)"; set -e
557 fi
558
559 # Start all daemons
560 cd $C_PATH/
561 if [ "$2" != "watchfrr" ]; then
562 start_prio 10 $dmn
563 fi
564 start_watchfrr
565 vtysh_b
566 ;;
567
568 1|2|3|4|5|6|7|8|9|10)
569 # Stop/start daemons for the appropriate priority level
570 stop_prio $1
571 start_prio $1
572 vtysh_b
573 ;;
574
575 stop|0)
576 # Stop all daemons at level '0' or 'stop'
577 stop_watchfrr
578 if [ "$dmn" != "watchfrr" ]; then
579 [ -n "${dmn}" ] && eval "${dmn/-/_}=0"
580 stop_prio 0 $dmn
581 fi
582
583 if [ -z "$dmn" -o "$dmn" = "zebra" ]; then
584 echo "Removing all routes made by FRR."
585 # Specific values for each proto can be found
586 # in /etc/iproute2/rt_protos as well as FRR
587 # specific ones in /etc/iproute2/rt_protos.d
588 # Additionally if a new protocol is added
589 # we need to add it here as well as
590 # in rt_netlink.h( follow the directions! )
591 ip route flush proto 4
592 ip route flush proto 11
593 ip route flush proto 42
594 ip route flush proto 186
595 ip route flush proto 187
596 ip route flush proto 188
597 ip route flush proto 189
598 ip route flush proto 190
599 ip route flush proto 191
600 ip route flush proto 192
601 ip route flush proto 193
602 ip route flush proto 194
603 ip route flush proto 195
604 ip route flush proto 196
605 else
606 [ -n "$dmn" ] && eval "${dmn/-/_}=0"
607 start_watchfrr
608 fi
609 ;;
610
611 reload)
612 # Just apply the commands that have changed, no restart necessary
613 if [ ! -x "$RELOAD_SCRIPT" ]; then
614 echo "Please install frr-pythontools package. Required for reload"
615 exit 0
616 fi
617
618 NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
619 [ ! -r $NEW_CONFIG_FILE ] && echo "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
620 echo "Applying only incremental changes to running configuration from frr.conf"
621 "$RELOAD_SCRIPT" --reload $C_PATH/frr.conf
622 exit $?
623 ;;
624
625 status)
626 check_status $dmn
627 exit $?
628 ;;
629
630 restart|force-reload)
631 $0 stop $dmn
632 sleep 1
633 $0 start $dmn
634 ;;
635
636 *)
637 echo "Usage: /etc/init.d/frr {start|stop|status|reload|restart|force-reload|<priority>} [daemon]"
638 echo " E.g. '/etc/init.d/frr 5' would start all daemons with a prio 1-5."
639 echo " reload applies only modifications from the running config to all daemons."
640 echo " reload neither restarts starts any daemon nor starts any new ones."
641 echo " Read /usr/share/doc/frr/README.Debian for details."
642 exit 1
643 ;;
644 esac
645
646 echo "Exiting from the script"
647 exit 0