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