You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

362 lines
7.9 KiB

  1. #!/bin/sh
  2. #
  3. #
  4. # This is a "library" of sorts for use by the other FRR shell scripts. It
  5. # has most of the daemon start/stop logic, but expects the following shell
  6. # functions/commands to be provided by the "calling" script:
  7. #
  8. # log_success_msg
  9. # log_warning_msg
  10. # log_failure_msg
  11. #
  12. # (coincidentally, these are LSB standard functions.)
  13. #
  14. # Sourcing this file in a shell script will load FRR config variables but
  15. # not perform any action. Note there is an "exit 1" if the main config
  16. # file does not exist.
  17. #
  18. # This script should be installed in /usr/sbin/frrcommon.sh
  19. # FRR_PATHSPACE is passed in from watchfrr
  20. suffix="${FRR_PATHSPACE:+/${FRR_PATHSPACE}}"
  21. nsopt="${FRR_PATHSPACE:+-N ${FRR_PATHSPACE}}"
  22. PATH=/bin:/usr/bin:/sbin:/usr/sbin
  23. D_PATH="/usr/sbin" # /usr/lib/frr
  24. C_PATH="/etc/frr" # /etc/frr
  25. V_PATH="/var/run/frr" # /var/run/frr
  26. VTYSH="/usr/bin/vtysh" # /usr/bin/vtysh
  27. FRR_USER="network" # frr
  28. FRR_GROUP="network" # frr
  29. FRR_VTY_GROUP="" # frrvty
  30. FRR_CONFIG_MODE="0600" # 0600
  31. FRR_DEFAULT_PROFILE="traditional" # traditional / datacenter
  32. # ORDER MATTERS FOR $DAEMONS!
  33. # - keep zebra first
  34. # - watchfrr does NOT belong in this list
  35. DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd"
  36. RELOAD_SCRIPT="$D_PATH/frr-reload.py"
  37. #
  38. # general helpers
  39. #
  40. debug() {
  41. [ -n "$watchfrr_debug" ] || return 0
  42. printf '%s %s(%s):' "`date +%Y-%m-%dT%H:%M:%S.%N`" "$0" $$ >&2
  43. # this is to show how arguments are split regarding whitespace & co.
  44. # (e.g. for use with `debug "message" "$@"`)
  45. while [ $# -gt 0 ]; do
  46. printf ' "%s"' "$1" >&2
  47. shift
  48. done
  49. printf '\n' >&2
  50. }
  51. chownfrr() {
  52. [ -n "$FRR_USER" ] && chown "$FRR_USER" "$1"
  53. [ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1"
  54. [ -n "$FRR_CONFIG_MODE" ] && chmod "$FRR_CONFIG_MODE" "$1"
  55. if [ -d "$1" ]; then
  56. chmod u+x "$1"
  57. fi
  58. }
  59. vtysh_b () {
  60. [ "$1" = "watchfrr" ] && return 0
  61. [ -r "$C_PATH/frr.conf" ] || return 0
  62. if [ -n "$1" ]; then
  63. "$VTYSH" `echo $nsopt` -b -d "$1"
  64. else
  65. "$VTYSH" `echo $nsopt` -b
  66. fi
  67. }
  68. daemon_inst() {
  69. # note this sets global variables ($dmninst, $daemon, $inst)
  70. dmninst="$1"
  71. daemon="${dmninst%-*}"
  72. inst=""
  73. [ "$daemon" != "$dmninst" ] && inst="${dmninst#*-}"
  74. }
  75. daemon_list() {
  76. # note $1 and $2 specify names for global variables to be set
  77. local enabled disabled evar dvar
  78. enabled=""
  79. disabled=""
  80. evar="$1"
  81. dvar="$2"
  82. for daemon in $DAEMONS; do
  83. eval cfg=\$$daemon
  84. eval inst=\$${daemon}_instances
  85. [ "$daemon" = zebra -o "$daemon" = staticd ] && cfg=yes
  86. if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then
  87. if ! daemon_prep "$daemon" "$inst"; then
  88. continue
  89. fi
  90. debug "$daemon enabled"
  91. # enabled="$enabled $daemon"
  92. if [ -n "$inst" ]; then
  93. debug "$daemon multi-instance $inst"
  94. oldifs="${IFS}"
  95. IFS="${IFS},"
  96. for i in $inst; do
  97. enabled="$enabled $daemon-$i"
  98. done
  99. IFS="${oldifs}"
  100. else
  101. enabled="$enabled $daemon"
  102. fi
  103. else
  104. debug "$daemon disabled"
  105. disabled="$disabled $daemon"
  106. fi
  107. done
  108. enabled="${enabled# }"
  109. disabled="${disabled# }"
  110. [ -z "$evar" ] && echo "$enabled"
  111. [ -n "$evar" ] && eval $evar="\"$enabled\""
  112. [ -n "$dvar" ] && eval $dvar="\"$disabled\""
  113. }
  114. #
  115. # individual daemon management
  116. #
  117. daemon_prep() {
  118. local daemon inst cfg
  119. daemon="$1"
  120. inst="$2"
  121. [ "$daemon" = "watchfrr" ] && return 0
  122. [ -x "$D_PATH/$daemon" ] || {
  123. log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed"
  124. return 1
  125. }
  126. [ -r "$C_PATH/frr.conf" ] && return 0
  127. cfg="$C_PATH/$daemon${inst:+-$inst}.conf"
  128. if [ ! -r "$cfg" ]; then
  129. touch "$cfg"
  130. chownfrr "$cfg"
  131. fi
  132. return 0
  133. }
  134. daemon_start() {
  135. local dmninst daemon inst args instopt wrap bin
  136. daemon_inst "$1"
  137. ulimit -n $MAX_FDS > /dev/null 2> /dev/null
  138. daemon_prep "$daemon" "$inst" || return 1
  139. if test ! -d "$V_PATH"; then
  140. mkdir -p "$V_PATH"
  141. chown $FRR_USER "$V_PATH"
  142. fi
  143. eval wrap="\$${daemon}_wrap"
  144. bin="$D_PATH/$daemon"
  145. instopt="${inst:+-n $inst}"
  146. eval args="\$${daemon}_options"
  147. if eval "$all_wrap $wrap $bin $nsopt -d $frr_global_options $instopt $args"; then
  148. log_success_msg "Started $dmninst"
  149. vtysh_b "$daemon"
  150. else
  151. log_failure_msg "Failed to start $dmninst!"
  152. fi
  153. }
  154. daemon_stop() {
  155. local dmninst daemon inst pidfile vtyfile pid cnt fail
  156. daemon_inst "$1"
  157. pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
  158. vtyfile="$V_PATH/$daemon${inst:+-$inst}.vty"
  159. [ -r "$pidfile" ] || fail="pid file not found"
  160. [ -z "$fail" ] && pid="`cat \"$pidfile\"`"
  161. [ -z "$fail" -a -z "$pid" ] && fail="pid file is empty"
  162. [ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running"
  163. if [ -n "$fail" ]; then
  164. log_failure_msg "Cannot stop $dmninst: $fail"
  165. return 1
  166. fi
  167. debug "kill -2 $pid"
  168. kill -2 "$pid"
  169. cnt=1200
  170. while kill -0 "$pid" 2>/dev/null; do
  171. sleep 1
  172. [ $(( cnt -= 1 )) -gt 0 ] || break
  173. done
  174. if kill -0 "$pid" 2>/dev/null; then
  175. log_failure_msg "Failed to stop $dmninst, pid $pid still running"
  176. still_running=1
  177. return 1
  178. else
  179. log_success_msg "Stopped $dmninst"
  180. rm -f "$pidfile"
  181. return 0
  182. fi
  183. }
  184. daemon_status() {
  185. local dmninst daemon inst pidfile pid fail
  186. daemon_inst "$1"
  187. pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
  188. [ -r "$pidfile" ] || return 3
  189. pid="`cat \"$pidfile\"`"
  190. [ -z "$pid" ] && return 1
  191. kill -0 "$pid" 2>/dev/null || return 1
  192. return 0
  193. }
  194. print_status() {
  195. daemon_status "$1"
  196. rv=$?
  197. if [ "$rv" -eq 0 ]; then
  198. log_success_msg "Status of $1: running"
  199. else
  200. log_failure_msg "Status of $1: FAILED"
  201. fi
  202. return $rv
  203. }
  204. #
  205. # all-daemon commands
  206. #
  207. all_start() {
  208. daemon_list daemons
  209. for dmninst in $daemons; do
  210. daemon_start "$dmninst"
  211. done
  212. }
  213. all_stop() {
  214. local pids reversed
  215. daemon_list daemons disabled
  216. [ "$1" = "--reallyall" ] && daemons="$daemons $disabled"
  217. reversed=""
  218. for dmninst in $daemons; do
  219. reversed="$dmninst $reversed"
  220. done
  221. for dmninst in $reversed; do
  222. daemon_stop "$dmninst" &
  223. pids="$pids $!"
  224. done
  225. for pid in $pids; do
  226. wait $pid
  227. done
  228. }
  229. all_status() {
  230. local fail
  231. daemon_list daemons
  232. fail=0
  233. for dmninst in $daemons; do
  234. print_status "$dmninst" || fail=1
  235. done
  236. return $fail
  237. }
  238. #
  239. # config sourcing
  240. #
  241. load_old_config() {
  242. oldcfg="$1"
  243. [ -r "$oldcfg" ] || return 0
  244. [ -s "$oldcfg" ] || return 0
  245. grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev/null || return 0
  246. log_warning_msg "Reading deprecated $oldcfg. Please move its settings to $C_PATH/daemons and remove it."
  247. # save off settings from daemons for the OR below
  248. for dmn in $DAEMONS; do eval "_new_$dmn=\${$dmn:-no}"; done
  249. . "$oldcfg"
  250. # OR together the daemon enabling options between config files
  251. for dmn in $DAEMONS; do eval "test \$_new_$dmn != no && $dmn=\$_new_$dmn; unset _new_$dmn"; done
  252. }
  253. [ -r "$C_PATH/daemons" ] || {
  254. log_failure_msg "cannot run $@: $C_PATH/daemons does not exist"
  255. exit 1
  256. }
  257. . "$C_PATH/daemons"
  258. if [ -z "$FRR_PATHSPACE" ]; then
  259. load_old_config "$C_PATH/daemons.conf"
  260. load_old_config "/etc/default/frr"
  261. load_old_config "/etc/sysconfig/frr"
  262. fi
  263. if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then
  264. log_warning_msg "watchfrr_options contains a bash array value." \
  265. "The configured value is intentionally ignored since it is likely wrong." \
  266. "Please remove or fix the setting."
  267. unset watchfrr_options
  268. fi
  269. if test -z "$frr_profile"; then
  270. # try to autodetect config profile
  271. if test -d /etc/cumulus; then
  272. frr_profile=datacenter
  273. # elif test ...; then
  274. # -- add your distro/system here
  275. elif test -n "$FRR_DEFAULT_PROFILE"; then
  276. frr_profile="$FRR_DEFAULT_PROFILE"
  277. fi
  278. fi
  279. test -n "$frr_profile" && frr_global_options="$frr_global_options -F $frr_profile"
  280. #
  281. # other defaults and dispatch
  282. #
  283. frrcommon_main() {
  284. local cmd
  285. debug "frrcommon_main" "$@"
  286. cmd="$1"
  287. shift
  288. if [ "$1" = "all" -o -z "$1" ]; then
  289. case "$cmd" in
  290. start) all_start;;
  291. stop) all_stop;;
  292. restart)
  293. all_stop
  294. all_start
  295. ;;
  296. *) $cmd "$@";;
  297. esac
  298. else
  299. case "$cmd" in
  300. start) daemon_start "$@";;
  301. stop) daemon_stop "$@";;
  302. restart)
  303. daemon_stop "$@"
  304. daemon_start "$@"
  305. ;;
  306. *) $cmd "$@";;
  307. esac
  308. fi
  309. }