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