]> git.proxmox.com Git - mirror_frr.git/blob - tools/frr
Merge pull request #377 from qlyoung/frr-pthreads
[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"
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 ${SSD} \
154 --start \
155 --pidfile=`pidfile $1` \
156 --exec "$D_PATH/$1" \
157 -- \
158 `eval echo "$""$1""_options"`
159 fi
160 }
161
162 # Stop the daemon given in the parameter, printing its name to the terminal.
163 stop()
164 {
165 local inst
166
167 if [ -n "$2" ]; then
168 inst="$1-$2"
169 else
170 inst="$1"
171 fi
172
173 if ! started "$inst" ; then
174 echo -n " ($inst)"
175 return 0
176 else
177 PIDFILE=`pidfile $inst`
178 PID=`cat $PIDFILE 2>/dev/null`
179 ${SSD} --stop --quiet --retry=TERM/30/KILL/5 --oknodo --pidfile "$PIDFILE" --exec "$D_PATH/$1"
180 #
181 # Now we have to wait until $DAEMON has _really_ stopped.
182 #
183 if test -n "$PID" && kill -0 $PID 2>/dev/null; then
184 echo -n " (waiting) ."
185 cnt=0
186 while kill -0 $PID 2>/dev/null; do
187 cnt=`expr $cnt + 1`
188 if [ $cnt -gt 60 ]; then
189 # Waited 120 secs now, fail.
190 echo -n "Failed.. "
191 break
192 fi
193 sleep 2
194 echo -n "."
195 done
196 fi
197 echo -n " $inst"
198 rm -f `pidfile $inst`
199 rm -f `vtyfile $inst`
200 fi
201 }
202
203 # Converts values from /etc/frr/daemons to all-numeric values.
204 convert_daemon_prios()
205 {
206 for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do
207 # First, assign the value set by the user to $value
208 eval value=\${${name}:0:3}
209
210 # Daemon not activated or entry missing?
211 if [ "$value" = "no" -o "$value" = "" ]; then value=0; fi
212
213 # These strings parsed for backwards compatibility.
214 if [ "$value" = "yes" -o "$value" = "true" ]; then
215 value=1;
216 fi
217
218 # Zebra is threatened special. It must be between 0=off and the first
219 # user assigned value "1" so we increase all other enabled daemons' values.
220 if [ "$name" != "zebra" -a "$value" -gt 0 ]; then value=`expr "$value" + 1`; fi
221
222 # If e.g. name is zebra then we set "zebra=yes".
223 eval $name=$value
224 done
225 }
226
227 # Starts watchfrr for all wanted daemons.
228 start_watchfrr()
229 {
230 local daemon_name
231 local daemon_prio
232 local found_one
233 local daemon_inst
234
235 # Start the monitor daemon only if desired.
236 if [ 0 -eq "$watchfrr_enable" ]; then
237 return
238 fi
239
240 # Check variable type
241 if ! declare -p watchfrr_options | grep -q '^declare \-a'; then
242 echo
243 echo "ERROR: The variable watchfrr_options from /etc/frr/debian.cnf must be a BASH array!"
244 echo "ERROR: Please convert config file and restart!"
245 exit 1
246 fi
247
248 # Which daemons have been started?
249 found_one=0
250 for daemon_name in $DAEMONS; do
251 eval daemon_prio=\$$daemon_name
252 if [ "$daemon_prio" -gt 0 ]; then
253 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
254 if [ -n "$daemon_inst" ]; then
255 for inst in ${daemon_inst}; do
256 eval "inst_disable=\${${daemon_name}_${inst}}"
257 if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then
258 if check_daemon $daemon_name $inst; then
259 watchfrr_options+=("${daemon_name}-${inst}")
260 fi
261 fi
262 done
263 else
264 if check_daemon $daemon_name; then
265 watchfrr_options+=($daemon_name)
266 fi
267 fi
268 found_one=1
269 fi
270 done
271
272 # Start if at least one daemon is activated.
273 if [ $found_one -eq 1 ]; then
274 echo -n "Starting Frr monitor daemon:"
275 start watchfrr
276 echo "."
277 fi
278 }
279
280 # Stopps watchfrr.
281 stop_watchfrr()
282 {
283 echo -n "Stopping Frr monitor daemon:"
284 stop watchfrr
285 echo "."
286 }
287
288 # Stops all daemons that have a lower level of priority than the given.
289 # (technically if daemon_prio >= wanted_prio)
290 stop_prio()
291 {
292 local wanted_prio
293 local daemon_prio
294 local daemon_list
295 local daemon_inst
296 local inst
297
298 if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
299 daemon=${BASH_REMATCH[1]}
300 inst=${BASH_REMATCH[2]}
301 else
302 daemon="$2"
303 fi
304
305 wanted_prio=$1
306 daemon_list=${daemon:-$DAEMONS}
307
308 echo -n "Stopping Frr daemons (prio:$wanted_prio):"
309
310 for prio_i in `seq 10 -1 $wanted_prio`; do
311 for daemon_name in $daemon_list; do
312 eval daemon_prio=\${${daemon_name}:0:3}
313 daemon_inst=""
314 if [ $daemon_prio -eq $prio_i ]; then
315 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
316 if [ -n "$daemon_inst" ]; then
317 for i in ${daemon_inst}; do
318 if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
319 stop "$daemon_name" "$inst"
320 elif [ x"$inst" == x ]; then
321 stop "$daemon_name" "$i"
322 fi
323 done
324 else
325 stop "$daemon_name"
326 fi
327 fi
328 done
329 done
330
331 echo "."
332 if [ -z "$inst" ]; then
333 # Now stop other daemons that're prowling, coz the daemons file changed
334 echo -n "Stopping other frr daemons"
335 if [ -n "$daemon" ]; then
336 eval "file_list_suffix="$V_PATH"/"$daemon*""
337 else
338 eval "file_list_suffix="$V_PATH/*""
339 fi
340 for pidfile in $file_list_suffix.pid; do
341 PID=`cat $pidfile 2>/dev/null`
342 ${SSD} --stop --quiet --oknodo --pidfile "$pidfile"
343 echo -n "."
344 rm -rf "$pidfile"
345 done
346 echo "."
347
348 echo -n "Removing remaining .vty files"
349 for vtyfile in $file_list_suffix.vty; do
350 rm -rf "$vtyfile"
351 done
352 echo "."
353 fi
354 }
355
356 # Starts all daemons that have a higher level of priority than the given.
357 # (technically if daemon_prio <= wanted_prio)
358 start_prio()
359 {
360 local wanted_prio
361 local daemon_prio
362 local daemon_list
363 local daemon_name
364 local daemon_inst
365 local inst
366
367 if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
368 daemon=${BASH_REMATCH[1]}
369 inst=${BASH_REMATCH[2]}
370 else
371 daemon="$2"
372 fi
373
374 wanted_prio=$1
375 daemon_list=${daemon:-$DAEMONS}
376
377 echo -n "Starting Frr daemons (prio:$wanted_prio):"
378
379 for prio_i in `seq 1 $wanted_prio`; do
380 for daemon_name in $daemon_list; do
381 eval daemon_prio=\$${daemon_name}
382 daemon_inst=""
383 if [ $daemon_prio -eq $prio_i ]; then
384 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
385 if [ -n "$daemon_inst" ]; then
386 if [ `echo "$daemon_inst" | wc -w` -gt ${MAX_INSTANCES} ]; then
387 echo "Max instances supported is ${MAX_INSTANCES}. Aborting"
388 exit 1
389 fi
390 # Check if we're starting again by switching from single instance
391 # to MI version
392 if started "$daemon_name"; then
393 PIDFILE=`pidfile $daemon_name`
394 ${SSD} \
395 --stop --quiet --oknodo \
396 --pidfile "$PIDFILE" \
397 --exec "$D_PATH/$daemon_name"
398
399 rm -f `pidfile $1`
400 rm -f `vtyfile $1`
401 fi
402
403 for i in ${daemon_inst}; do
404 if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
405 start "$daemon_name" "$inst"
406 elif [ x"$inst" == x ]; then
407 start "$daemon_name" "$i"
408 fi
409 done
410 else
411 # Check if we're starting again by switching from
412 # single instance to MI version
413 eval "file_list_suffix="$V_PATH"/"$daemon_name-*""
414 for pidfile in $file_list_suffix.pid; do
415 ${SSD} --stop --quiet --oknodo --pidfile "$pidfile"
416 echo -n "."
417 rm -rf "$pidfile"
418 done
419 for vtyfile in $file_list_suffix.vty; do
420 rm -rf "$vtyfile"
421 done
422
423 start "$daemon_name"
424 fi
425 fi
426 done
427 done
428 echo "."
429 }
430
431 check_status()
432 {
433 local daemon_name
434 local daemon_prio
435 local daemon_inst
436 local failed_status=0
437
438 if [ -n "$1" ] && [[ "$1" =~ (.*)-(.*) ]]; then
439 daemon=${BASH_REMATCH[1]}
440 inst=${BASH_REMATCH[2]}
441 else
442 daemon="$1"
443 fi
444
445 daemon_list=${daemon:-$DAEMONS}
446
447 # Which daemons have been started?
448 for daemon_name in $daemon_list; do
449 eval daemon_prio=\$$daemon_name
450 if [ "$daemon_prio" -gt 0 ]; then
451 eval "daemon_inst=\${${daemon_name}_instances//,/ }"
452 if [ -n "$daemon_inst" ]; then
453 for i in ${daemon_inst}; do
454 if [ -n "$inst" -a "$inst" = "$i" ]; then
455 started "$1" "log" || failed_status=$?
456 elif [ -z "$inst" ]; then
457 started "$daemon_name-$i" "log" || failed_status=$?
458 fi
459 done
460 else
461 started "$daemon_name" "log" || failed_status=$?
462 fi
463 fi
464 done
465
466 # All daemons that need to have been started are up and running
467 return $failed_status
468 }
469
470 #########################################################
471 # Main program #
472 #########################################################
473
474 # Config broken but script must exit silently.
475 [ ! -r "$C_PATH/daemons" ] && exit 0
476
477 # Load configuration
478 . "$C_PATH/daemons"
479 . "$C_PATH/debian.conf"
480
481 # Read configuration variable file if it is present
482 [ -r /etc/default/frr ] && . /etc/default/frr
483
484 MAX_INSTANCES=${MAX_INSTANCES:=5}
485
486 # Set priority of un-startable daemons to 'no' and substitute 'yes' to '0'
487 convert_daemon_prios
488
489 if [ ! -d $V_PATH ]; then
490 echo "Creating $V_PATH"
491 mkdir -p $V_PATH
492 chown frr:frr $V_PATH
493 chmod 755 /$V_PATH
494 fi
495
496 if [ -n "$3" ] && [ "$3" != "all" ]; then
497 dmn="$2"-"$3"
498 elif [ -n "$2" ] && [ "$2" != "all" ]; then
499 dmn="$2"
500 fi
501
502 case "$1" in
503 start)
504 # Try to load this necessary (at least for 2.6) module.
505 if [ -d /lib/modules/`uname -r` ] ; then
506 echo "Loading capability module if not yet done."
507 set +e; LC_ALL=C modprobe -a capability 2>&1 | egrep -v "(not found|Can't locate)"; set -e
508 fi
509
510 # Start all daemons
511 cd $C_PATH/
512 if [ "$2" != "watchfrr" ]; then
513 start_prio 10 $dmn
514 fi
515 start_watchfrr
516 vtysh_b
517 ;;
518
519 1|2|3|4|5|6|7|8|9|10)
520 # Stop/start daemons for the appropriate priority level
521 stop_prio $1
522 start_prio $1
523 vtysh_b
524 ;;
525
526 stop|0)
527 # Stop all daemons at level '0' or 'stop'
528 stop_watchfrr
529 if [ "$dmn" != "watchfrr" ]; then
530 [ -n "${dmn}" ] && eval "${dmn/-/_}=0"
531 stop_prio 0 $dmn
532 fi
533
534 if [ -z "$dmn" -o "$dmn" = "zebra" ]; then
535 echo "Removing all routes made by FRR."
536 ip route flush proto bgp
537 ip route flush proto ospf
538 ip route flush proto static
539 ip route flush proto rip
540 ip route flush proto ripng
541 ip route flush proto zebra
542 ip route flush proto isis
543
544 else
545 [ -n "$dmn" ] && eval "${dmn/-/_}=0"
546 start_watchfrr
547 fi
548 ;;
549
550 reload)
551 # Just apply the commands that have changed, no restart necessary
552 [ ! -x "$RELOAD_SCRIPT" ] && echo "frr-reload script not available" && exit 0
553 NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
554 [ ! -r $NEW_CONFIG_FILE ] && echo "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
555 echo "Applying only incremental changes to running configuration from frr.conf"
556 "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf
557 exit $?
558 ;;
559
560 status)
561 check_status $dmn
562 exit $?
563 ;;
564
565 restart|force-reload)
566 $0 stop $dmn
567 sleep 1
568 $0 start $dmn
569 ;;
570
571 *)
572 echo "Usage: /etc/init.d/frr {start|stop|status|reload|restart|force-reload|<priority>} [daemon]"
573 echo " E.g. '/etc/init.d/frr 5' would start all daemons with a prio 1-5."
574 echo " reload applies only modifications from the running config to all daemons."
575 echo " reload neither restarts starts any daemon nor starts any new ones."
576 echo " Read /usr/share/doc/frr/README.Debian for details."
577 exit 1
578 ;;
579 esac
580
581 echo "Exiting from the script"
582 exit 0