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