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