]> git.proxmox.com Git - mirror_frr.git/blob - tools/frr.in
Merge pull request #3276 from donaldsharp/zclient_update
[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 ulimit -n $MAX_FDS
119 if [ "$1" = "watchfrr" ]; then
120
121 # We may need to restart watchfrr if new daemons are added and/or
122 # removed
123 if started "$1" ; then
124 stop watchfrr
125 else
126 # Echo only once. watchfrr is printed in the stop above
127 echo -n " $1"
128 fi
129
130
131 ${SSD} \
132 --start \
133 --pidfile=`pidfile $1` \
134 --exec "$D_PATH/$1" \
135 -- \
136 "${watchfrr_options[@]}"
137
138 elif [ -n "$2" ]; then
139 echo -n " $1-$2"
140 if ! check_daemon $1 $2 ; then
141 echo -n " (binary does not exist)"
142 return;
143 fi
144
145 ${SSD} \
146 --start \
147 --pidfile=`pidfile $1-$2` \
148 --exec "$D_PATH/$1" \
149 -- \
150 `eval echo "$""$1""_options"` -n "$2"
151 else
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 cnt=0
214 while kill -0 $PID 2>/dev/null; do
215 cnt=`expr $cnt + 1`
216 if [ $cnt -gt 60 ]; then
217 # Waited 120 secs now, fail.
218 echo -n "Failed.. "
219 break
220 fi
221 sleep 2
222 done
223 fi
224 rm -f `pidfile $inst`
225 rm -f `vtyfile $inst`
226
227 if [ "$1" = "zebra" ]; then
228 echo -n "Stopping staticd since zebra is running"
229 stop staticd
230 fi
231 fi
232 }
233
234 # Converts values from /etc/frr/daemons to all-numeric values.
235 convert_daemon_prios()
236 {
237 for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do
238 # First, assign the value set by the user to $value
239 eval value=\${${name}:0:3}
240
241 # Daemon not activated or entry missing?
242 if [ "$value" = "no" -o "$value" = "" ]; then value=0; fi
243
244 # These strings parsed for backwards compatibility.
245 if [ "$value" = "yes" -o "$value" = "true" ]; then
246 value=1;
247 fi
248
249 # Zebra is threatened special. It must be between 0=off and the first
250 # user assigned value "1" so we increase all other enabled daemons' values.
251 if [ "$name" != "zebra" -a "$value" -gt 0 ]; then value=`expr "$value" + 1`; fi
252
253 # If e.g. name is zebra then we set "zebra=yes".
254 eval $name=$value
255 done
256 }
257
258 # Starts watchfrr for all wanted daemons.
259 start_watchfrr()
260 {
261 local daemon_name
262 local daemon_prio
263 local found_one
264 local daemon_inst
265
266 # Start the monitor daemon only if desired.
267 if [ 0 -eq "$watchfrr_enable" ]; then
268 return
269 fi
270
271 # Check variable type
272 if ! declare -p watchfrr_options | grep -q '^declare \-a'; then
273 echo
274 echo "ERROR: The variable watchfrr_options from /etc/frr/debian.cnf must be a BASH array!"
275 echo "ERROR: Please convert config file and restart!"
276 exit 1
277 fi
278
279 # Which daemons have been started?
280 found_one=0
281 for daemon_name in $DAEMONS; do
282 eval daemon_prio=\$$daemon_name
283 if [ "$daemon_prio" -gt 0 ]; then
284 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
285 if [ -n "$daemon_inst" ]; then
286 for inst in ${daemon_inst}; do
287 eval "inst_disable=\${${daemon_name}_${inst}}"
288 if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then
289 if check_daemon $daemon_name $inst; then
290 watchfrr_options+=("${daemon_name}-${inst}")
291 fi
292 fi
293 done
294 else
295 if check_daemon $daemon_name; then
296 watchfrr_options+=($daemon_name)
297 fi
298 fi
299 found_one=1
300 fi
301 done
302
303 # Start if at least one daemon is activated.
304 if [ $found_one -eq 1 ]; then
305 start watchfrr
306 echo "."
307 fi
308 }
309
310 # Stopps watchfrr.
311 stop_watchfrr()
312 {
313 echo -n "Stopping Frr monitor daemon:"
314 stop watchfrr
315 echo "."
316 }
317
318 # Stops all daemons that have a lower level of priority than the given.
319 # (technically if daemon_prio >= wanted_prio)
320 stop_prio()
321 {
322 local wanted_prio
323 local daemon_prio
324 local daemon_list
325 local daemon_inst
326 local inst
327
328 if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
329 daemon=${BASH_REMATCH[1]}
330 inst=${BASH_REMATCH[2]}
331 else
332 daemon="$2"
333 fi
334
335 wanted_prio=$1
336 daemon_list=${daemon:-$DAEMONS}
337
338 echo -n "Stopping Frr daemons (prio:$wanted_prio):"
339
340 for prio_i in `seq 10 -1 $wanted_prio`; do
341 for daemon_name in $daemon_list; do
342 eval daemon_prio=\${${daemon_name}:0:3}
343 daemon_inst=""
344 if [ $daemon_prio -eq $prio_i ]; then
345 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
346 if [ -n "$daemon_inst" ]; then
347 for i in ${daemon_inst}; do
348 if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
349 stop "$daemon_name" "$inst"
350 elif [ x"$inst" == x ]; then
351 stop "$daemon_name" "$i"
352 fi
353 done
354 else
355 stop "$daemon_name"
356 fi
357 fi
358 done
359 done
360
361 echo "."
362 if [ -z "$inst" ]; then
363 # Now stop other daemons that're prowling, coz the daemons file changed
364 echo -n "Stopping other frr daemons"
365 if [ -n "$daemon" ]; then
366 eval "file_list_suffix="$V_PATH"/"$daemon*""
367 else
368 eval "file_list_suffix="$V_PATH/*""
369 fi
370 for pidfile in $file_list_suffix.pid; do
371 PID=`cat $pidfile 2>/dev/null`
372 ${SSD} --stop --quiet --oknodo --pidfile "$pidfile"
373 echo -n "."
374 rm -rf "$pidfile"
375 done
376 echo "."
377
378 echo -n "Removing remaining .vty files"
379 for vtyfile in $file_list_suffix.vty; do
380 rm -rf "$vtyfile"
381 done
382 echo "."
383 fi
384 }
385
386 # Starts all daemons that have a higher level of priority than the given.
387 # (technically if daemon_prio <= wanted_prio)
388 start_prio()
389 {
390 local wanted_prio
391 local daemon_prio
392 local daemon_list
393 local daemon_name
394 local daemon_inst
395 local inst
396
397 if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
398 daemon=${BASH_REMATCH[1]}
399 inst=${BASH_REMATCH[2]}
400 else
401 daemon="$2"
402 fi
403
404 wanted_prio=$1
405 daemon_list=${daemon:-$DAEMONS}
406
407 for prio_i in `seq 1 $wanted_prio`; do
408 for daemon_name in $daemon_list; do
409 eval daemon_prio=\$${daemon_name}
410 daemon_inst=""
411 if [ $daemon_prio -eq $prio_i ]; then
412 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
413 if [ -n "$daemon_inst" ]; then
414 if [ `echo "$daemon_inst" | wc -w` -gt ${MAX_INSTANCES} ]; then
415 echo "Max instances supported is ${MAX_INSTANCES}. Aborting"
416 exit 1
417 fi
418 # Check if we're starting again by switching from single instance
419 # to MI version
420 if started "$daemon_name"; then
421 PIDFILE=`pidfile $daemon_name`
422 ${SSD} \
423 --stop --quiet --oknodo \
424 --pidfile "$PIDFILE" \
425 --exec "$D_PATH/$daemon_name"
426
427 rm -f `pidfile $1`
428 rm -f `vtyfile $1`
429 fi
430
431 for i in ${daemon_inst}; do
432 if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
433 start "$daemon_name" "$inst"
434 elif [ x"$inst" == x ]; then
435 start "$daemon_name" "$i"
436 fi
437 done
438 else
439 # Check if we're starting again by switching from
440 # single instance to MI version
441 eval "file_list_suffix="$V_PATH"/"$daemon_name-*""
442 for pidfile in $file_list_suffix.pid; do
443 ${SSD} --stop --quiet --oknodo --pidfile "$pidfile"
444 rm -rf "$pidfile"
445 done
446 for vtyfile in $file_list_suffix.vty; do
447 rm -rf "$vtyfile"
448 done
449
450 start "$daemon_name"
451 fi
452 fi
453 done
454 done
455 }
456
457 check_status()
458 {
459 local daemon_name
460 local daemon_prio
461 local daemon_inst
462 local failed_status=0
463
464 if [ -n "$1" ] && [[ "$1" =~ (.*)-(.*) ]]; then
465 daemon=${BASH_REMATCH[1]}
466 inst=${BASH_REMATCH[2]}
467 else
468 daemon="$1"
469 fi
470
471 daemon_list=${daemon:-$DAEMONS}
472
473 # Which daemons have been started?
474 for daemon_name in $daemon_list; do
475 eval daemon_prio=\$$daemon_name
476 if [ "$daemon_prio" -gt 0 ]; then
477 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
478 if [ -n "$daemon_inst" ]; then
479 for i in ${daemon_inst}; do
480 if [ -n "$inst" -a "$inst" = "$i" ]; then
481 started "$1" "log" || failed_status=$?
482 elif [ -z "$inst" ]; then
483 started "$daemon_name-$i" "log" || failed_status=$?
484 fi
485 done
486 else
487 started "$daemon_name" "log" || failed_status=$?
488 fi
489 fi
490 done
491
492 # All daemons that need to have been started are up and running
493 return $failed_status
494 }
495
496 #########################################################
497 # Main program #
498 #########################################################
499
500 # Config broken but script must exit silently.
501 [ ! -r "$C_PATH/daemons" ] && exit 0
502
503 # Load configuration
504 . "$C_PATH/daemons"
505 . "$C_PATH/daemons.conf"
506
507 # Read configuration variable file if it is present
508 [ -r /etc/default/frr ] && . /etc/default/frr
509
510 MAX_INSTANCES=${MAX_INSTANCES:=5}
511
512 # Set priority of un-startable daemons to 'no' and substitute 'yes' to '0'
513 convert_daemon_prios
514
515 if [ ! -d $V_PATH ]; then
516 echo "Creating $V_PATH"
517 mkdir -p $V_PATH
518 chownfrr $V_PATH
519 chmod 755 /$V_PATH
520 fi
521
522 if [ -n "$3" ] && [ "$3" != "all" ]; then
523 dmn="$2"-"$3"
524 elif [ -n "$2" ] && [ "$2" != "all" ]; then
525 dmn="$2"
526 fi
527
528 case "$1" in
529 start)
530 # Try to load this necessary (at least for 2.6) module.
531 if [ -d /lib/modules/`uname -r` ] ; then
532 echo "Loading capability module if not yet done."
533 set +e; LC_ALL=C modprobe -a capability 2>&1 | egrep -v "(not found|Can't locate)"; set -e
534 fi
535
536 # Start all daemons
537 cd $C_PATH/
538 if [ "$2" != "watchfrr" ]; then
539 start_prio 10 $dmn
540 fi
541 start_watchfrr
542 vtysh_b
543 ;;
544
545 1|2|3|4|5|6|7|8|9|10)
546 # Stop/start daemons for the appropriate priority level
547 stop_prio $1
548 start_prio $1
549 vtysh_b
550 ;;
551
552 stop|0)
553 # Stop all daemons at level '0' or 'stop'
554 stop_watchfrr
555 if [ "$dmn" != "watchfrr" ]; then
556 [ -n "${dmn}" ] && eval "${dmn/-/_}=0"
557 stop_prio 0 $dmn
558 fi
559
560 if [ -z "$dmn" -o "$dmn" = "zebra" ]; then
561 echo "Removing all routes made by FRR."
562 # Specific values for each proto can be found
563 # in /etc/iproute2/rt_protos as well as FRR
564 # specific ones in /etc/iproute2/rt_protos.d
565 # Additionally if a new protocol is added
566 # we need to add it here as well as
567 # in rt_netlink.h( follow the directions! )
568 ip route flush proto 4
569 ip route flush proto 11
570 ip route flush proto 42
571 ip route flush proto 186
572 ip route flush proto 187
573 ip route flush proto 188
574 ip route flush proto 189
575 ip route flush proto 190
576 ip route flush proto 191
577 ip route flush proto 192
578 ip route flush proto 193
579 ip route flush proto 194
580 ip route flush proto 195
581 ip route flush proto 196
582 ip route flush proto 197
583 else
584 [ -n "$dmn" ] && eval "${dmn/-/_}=0"
585 start_watchfrr
586 fi
587 ;;
588
589 reload)
590 # Just apply the commands that have changed, no restart necessary
591 if [ ! -x "$RELOAD_SCRIPT" ]; then
592 echo "Please install frr-pythontools package. Required for reload"
593 exit 0
594 fi
595
596 NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
597 [ ! -r $NEW_CONFIG_FILE ] && echo "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
598 echo "Applying only incremental changes to running configuration from frr.conf"
599 "$RELOAD_SCRIPT" --reload $C_PATH/frr.conf
600 exit $?
601 ;;
602
603 status)
604 check_status $dmn
605 exit $?
606 ;;
607
608 restart|force-reload)
609 $0 stop $dmn
610 sleep 1
611 $0 start $dmn
612 ;;
613
614 *)
615 echo "Usage: /etc/init.d/frr {start|stop|status|reload|restart|force-reload|<priority>} [daemon]"
616 echo " E.g. '/etc/init.d/frr 5' would start all daemons with a prio 1-5."
617 echo " reload applies only modifications from the running config to all daemons."
618 echo " reload neither restarts starts any daemon nor starts any new ones."
619 echo " Read /usr/share/doc/frr/README.Debian for details."
620 exit 1
621 ;;
622 esac
623
624 echo "Exiting from the script"
625 exit 0