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.

548 lines
14 KiB

  1. #!/bin/sh /etc/rc.common
  2. # Copyright (C) 2007-2015 OpenWrt.org
  3. START=70
  4. STOP=01
  5. USE_PROCD=1
  6. KEEPALIVED_CONF=/tmp/keepalived.conf
  7. INDENT_1="\t"
  8. INDENT_2="${INDENT_1}${INDENT_1}"
  9. INDENT_3="${INDENT_1}${INDENT_1}${INDENT_1}"
  10. INDENT_4="${INDENT_1}${INDENT_1}${INDENT_1}${INDENT_1}"
  11. config_section_open() {
  12. local tag="$1"
  13. local name="$2"
  14. printf '%s' "$tag" >> "$KEEPALIVED_CONF"
  15. [ -n "$name" ] && printf ' %s' "$name" >> "$KEEPALIVED_CONF"
  16. printf ' {\n' >> "$KEEPALIVED_CONF"
  17. }
  18. config_section_close() {
  19. printf '}\n\n' >> "$KEEPALIVED_CONF"
  20. }
  21. config_foreach_wrapper() {
  22. local section="$1"
  23. local function="$1"
  24. # Convention is that 'function' and 'section' are the same
  25. config_foreach "$function" "$section"
  26. }
  27. print_elems_indent() {
  28. local config="$1"
  29. shift
  30. local indent="$1"
  31. shift
  32. [ -z "$indent" ] && indent="$INDENT_1"
  33. for opt in "$@"; do
  34. local "$opt"
  35. local optval
  36. local no_val=0
  37. if [ "${opt:0:7}" = "no_val_" ]; then
  38. opt="${opt:7}"
  39. no_val=1
  40. fi
  41. config_get "$opt" "$config" "$opt"
  42. eval optval=\$"$opt"
  43. [ -z "$optval" ] && continue
  44. printf '%b%s' "$indent" "$opt" >> "$KEEPALIVED_CONF"
  45. [ "$no_val" = "0" ] && {
  46. local words=0
  47. words="$(echo "$optval" | wc -w)"
  48. if [ "$words" -gt 1 ]; then
  49. printf ' "%s"' "$optval" >> "$KEEPALIVED_CONF"
  50. else
  51. printf ' %s' "$optval" >> "$KEEPALIVED_CONF"
  52. fi
  53. }
  54. printf '\n' >> "$KEEPALIVED_CONF"
  55. done
  56. unset optval
  57. }
  58. print_list_indent() {
  59. local lst="$1"
  60. local indent="$2"
  61. local lst_elems
  62. [ -z "$indent" ] && indent="$INDENT_1"
  63. eval lst_elems=\$"$lst"
  64. [ -z "$lst_elems" ] && return 0
  65. printf '%b%s {\n' "$indent" "$lst" >> "$KEEPALIVED_CONF"
  66. for e in $lst_elems; do
  67. printf '%b%s\n' "${indent}${INDENT_1}" "$e">> "$KEEPALIVED_CONF"
  68. done
  69. printf '%b}\n' "$indent" >> "$KEEPALIVED_CONF"
  70. }
  71. print_notify() {
  72. local type="$1"
  73. shift
  74. local name="$1"
  75. shift
  76. for notify in "$@"; do
  77. printf '%b%s' "${INDENT_1}" "$notify">> "$KEEPALIVED_CONF"
  78. notify="$(echo "$notify" | tr 'a-z' 'A-Z')"
  79. printf ' "/bin/busybox env -i ACTION=%s TYPE=%s NAME=%s /sbin/hotplug-call keepalived"\n' "$notify" "$type" "$name" >> "$KEEPALIVED_CONF"
  80. done
  81. }
  82. globals() {
  83. local notification_email
  84. printf '%bscript_user root\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
  85. printf '%benabled_script_security\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
  86. config_get notification_email "$1" notification_email
  87. print_list_indent notification_email
  88. print_elems_indent "$1" "$INDENT_1" \
  89. notification_email_from \
  90. smtp_server \
  91. smtp_connect_timeout \
  92. router_id \
  93. vrrp_mcast_group4 \
  94. vrrp_mcast_group6 \
  95. vrrp_startup_delay
  96. }
  97. print_ipaddress_indent() {
  98. local section="$1"
  99. local curr_ipaddr="$2"
  100. local indent="$3"
  101. local address device scope name
  102. config_get name "$section" name
  103. [ "$name" != "$curr_ipaddr" ] && return 0
  104. config_get address "$section" address
  105. config_get device "$section" device
  106. config_get scope "$section" scope
  107. # Default indent
  108. [ -z "$indent" ] && indent="$INDENT_1"
  109. # If no address exit
  110. [ -z "$address" ] && return 0
  111. if [ -z "$device" ]; then
  112. printf '%b%s' "$indent" "$address" >> "$KEEPALIVED_CONF"
  113. else
  114. # Add IP address/netmask and device
  115. printf '%b%s dev %s' "$indent" "$address" "$device">> "$KEEPALIVED_CONF"
  116. # Add scope
  117. [ -n "$scope" ] && printf ' scope %s' "$scope" >> "$KEEPALIVED_CONF"
  118. fi
  119. printf '\n' >> "$KEEPALIVED_CONF"
  120. }
  121. static_ipaddress() {
  122. local address
  123. config_get address "$1" address
  124. for a in $address; do
  125. config_foreach print_ipaddress_indent ipaddress "$a"
  126. done
  127. }
  128. print_route_indent() {
  129. local section="$1"
  130. local curr_route="$2"
  131. local indent="$3"
  132. local name blackhole address src_addr gateway device scope table
  133. config_get name "$section" name
  134. [ "$name" != "$curr_route" ] && return 0
  135. config_get_bool blackhole "$section" blackhole 0
  136. config_get address "$section" address
  137. config_get src_addr "$section" src_addr
  138. config_get gateway "$section" gateway
  139. config_get device "$section" device
  140. config_get table "$section" table
  141. # If no address exit
  142. [ -z "$address" ] && return 0
  143. # Default indent
  144. [ -z "$indent" ] && indent="$INDENT_1"
  145. [ "$blackhole" -gt 0 ] && {
  146. printf '%bblackhole %s\n' "$indent" "$address" >> "$KEEPALIVED_CONF"
  147. return 0
  148. }
  149. # Add src addr or address
  150. if [ -n "$src_addr" ]; then
  151. printf '%bsrc %s %s' "$indent" "$src_addr" "$address" >> "$KEEPALIVED_CONF"
  152. else
  153. [ -z "$device" ] && return 0
  154. printf '%b%s' "$indent" "$address" >> "$KEEPALIVED_CONF"
  155. fi
  156. # Add route/gateway
  157. [ -n "$gateway" ] && printf ' via %s' "$gateway" >> "$KEEPALIVED_CONF"
  158. # Add device
  159. printf ' dev %s' "$device" >> "$KEEPALIVED_CONF"
  160. # Add scope
  161. [ -n "$scope" ] && printf ' scope %s' "$scope" >> "$KEEPALIVED_CONF"
  162. # Add table
  163. [ -n "$table" ] && printf ' table %s' "$table" >> "$KEEPALIVED_CONF"
  164. printf '\n' >> "$KEEPALIVED_CONF"
  165. }
  166. print_track_elem_indent() {
  167. local section="$1"
  168. local curr_track_elem="$2"
  169. local indent="$3"
  170. local name value
  171. config_get name "$section" name
  172. [ "$name" != "$curr_track_elem" ] && return 0
  173. config_get value "$section" value
  174. config_get weight "$section" weight
  175. [ -z "$value" ] && return 0
  176. printf '%b%s' "$indent" "$value" >> "$KEEPALIVED_CONF"
  177. [ -n "$weight" ] && printf ' weight %s' "$weight" >> "$KEEPALIVED_CONF"
  178. printf '\n' >> "$KEEPALIVED_CONF"
  179. }
  180. static_routes() {
  181. local route
  182. config_get route "$1" route
  183. for r in $route; do
  184. config_foreach print_route_indent route "$r"
  185. done
  186. }
  187. # Count 'vrrp_instance' with the given name ; called by vrrp_instance_check()
  188. vrrp_instance_name_count() {
  189. local name
  190. config_get name "$1" name
  191. [ "$name" = "$2" ] && count="$((count + 1))"
  192. }
  193. # Check if there's a 'vrrp_instance' section with the given name
  194. vrrp_instance_check() {
  195. local count="0"
  196. local name="$1"
  197. config_foreach vrrp_instance_name_count vrrp_instance "$name"
  198. [ $count -gt 0 ] && return 0 || return 1
  199. }
  200. vrrp_sync_group() {
  201. local group name
  202. local valid_group
  203. # No name for group, exit
  204. config_get name "$1" name
  205. [ -z "$name" ] && return 0
  206. # No members for group, exit
  207. config_get group "$1" group
  208. [ -z "$group" ] && return 0
  209. # Check if we have 'vrrp_instance's defined for
  210. # each member and remove names with not vrrp_instance defined
  211. for m in $group; do
  212. vrrp_instance_check "$m" && valid_group="$valid_group $m"
  213. done
  214. [ -z "$valid_group" ] && return 0
  215. config_section_open "vrrp_sync_group" "$name"
  216. group="$valid_group"
  217. print_list_indent group
  218. print_elems_indent "$1" "$INDENT_1" no_val_smtp_alert no_val_global_tracking
  219. print_notify "GROUP" "$name" notify_backup notify_master \
  220. notify_fault notify
  221. config_section_close
  222. }
  223. vrrp_instance() {
  224. local name auth_type auth_pass
  225. config_get name "$1" name
  226. [ -z "$name" ] && return 0
  227. config_section_open "vrrp_instance" "$name"
  228. config_get auth_type "$1" auth_type
  229. config_get auth_pass "$1" auth_pass
  230. [ -n "$auth_type" ] && [ -n "$auth_pass" ] && {
  231. printf '%bauthentication {\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
  232. printf '%bauth_type %s\n' "${INDENT_2}" "$auth_type" >> "$KEEPALIVED_CONF"
  233. printf '%bauth_pass %s\n' "${INDENT_2}" "$auth_pass" >> "$KEEPALIVED_CONF"
  234. printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
  235. }
  236. print_elems_indent "$1" "$INDENT_1" state interface \
  237. mcast_src_ip unicast_src_ip virtual_router_id version priority \
  238. advert_int preempt_delay debug \
  239. lvs_sync_daemon_interface garp_master_delay garp_master_refresh \
  240. garp_master_repeat garp_master_refresh_repeat \
  241. no_val_vmac_xmit_base no_val_native_ipv6 no_val_accept \
  242. no_val_dont_track_primary no_val_smtp_alert no_val_nopreempt \
  243. no_val_use_vmac
  244. print_notify "INSTANCE" "$name" notify_backup notify_master \
  245. notify_fault notify_stop
  246. # Handle virtual_ipaddress & virtual_ipaddress_excluded lists
  247. for opt in virtual_ipaddress virtual_ipaddress_excluded; do
  248. config_get "$opt" "$1" "$opt"
  249. eval optval=\$$opt
  250. [ -z "$optval" ] && continue
  251. printf '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
  252. for a in $optval; do
  253. config_foreach print_ipaddress_indent ipaddress "$a" "$INDENT_2"
  254. done
  255. printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
  256. done
  257. # Handle virtual_routes
  258. for opt in virtual_routes; do
  259. config_get "$opt" "$1" "$opt"
  260. eval optval=\$$opt
  261. [ -z "$optval" ] && continue
  262. printf '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
  263. for r in $optval; do
  264. config_foreach print_route_indent route "$r" "$INDENT_2"
  265. done
  266. printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
  267. done
  268. # Handle track_script lists
  269. for opt in track_script; do
  270. config_get "$opt" "$1" "$opt"
  271. eval optval=\$$opt
  272. [ -z "$optval" ] && continue
  273. printf '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
  274. for t in $optval; do
  275. printf '%b%s\n' "${INDENT_2}" "$optval" >> "$KEEPALIVED_CONF"
  276. done
  277. printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
  278. done
  279. # Handle track_interface lists
  280. for opt in track_interface; do
  281. config_get "$opt" "$1" "$opt"
  282. eval optval=\$$opt
  283. [ -z "$optval" ] && continue
  284. printf '%b%s {\n' "${INDENT_1}" "$opt" >> "$KEEPALIVED_CONF"
  285. for t in $optval; do
  286. config_foreach print_track_elem_indent track_interface "$t" "$INDENT_2"
  287. done
  288. printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
  289. done
  290. # Handle simple lists of strings (with no spaces in between)
  291. for opt in unicast_peer; do
  292. config_get "$opt" "$1" "$opt"
  293. print_list_indent "$opt"
  294. done
  295. unset optval
  296. config_section_close
  297. }
  298. vrrp_script() {
  299. local name
  300. config_get name "$1" name
  301. [ -z "$name" ] && return 0
  302. config_section_open "vrrp_script" "$name"
  303. print_elems_indent "$1" "$INDENT_1" script interval weight fall rise
  304. config_section_close
  305. }
  306. url() {
  307. local url="$2"
  308. local name path digest
  309. config_get name "$1" name
  310. [ "$url" = "$name" ] || return 0
  311. config_get path "$1" path
  312. config_get digest "$1" digest
  313. [ -n "$digest" ] && [ -n "$path" ] && {
  314. printf '%burl {\n' "${INDENT_3}" >> "$KEEPALIVED_CONF"
  315. printf '%bpath %s\n' "${INDENT_4}" "$path" >> "$KEEPALIVED_CONF"
  316. printf '%bdigest %s\n' "${INDENT_4}" "$digest" >> "$KEEPALIVED_CONF"
  317. printf '%b}\n' "${INDENT_3}" >> "$KEEPALIVED_CONF"
  318. }
  319. }
  320. url_list() {
  321. config_foreach url url "$1"
  322. }
  323. real_server() {
  324. local server="$2"
  325. local enabled name weight ipaddr port check
  326. config_get_bool enabled "$1" enabled 1
  327. [ "$enabled" -eq 1 ] || return 0
  328. config_get name "$1" name
  329. [ "$server" = "$name" ] || return 0
  330. config_get weight "$1" weight
  331. [ -n "$weight" ] || return 0
  332. config_get ipaddr "$1" ipaddr
  333. config_get port "$1" port
  334. config_get check "$1" check
  335. [ -n "$ipaddr" ] && [ -n "$port" ] && {
  336. printf '%breal_server %s %d {\n' "${INDENT_1}" "$ipaddr" "$port" >> "$KEEPALIVED_CONF"
  337. printf '%bweight %d\n' "${INDENT_2}" "$weight" >> "$KEEPALIVED_CONF"
  338. case "$check" in
  339. TCP_CHECK)
  340. printf '%b%s {\n' "${INDENT_2}" "$check" >> "$KEEPALIVED_CONF"
  341. print_elems_indent "$1" "$INDENT_3" connect_timeout \
  342. connect_port
  343. printf '%b}\n' "${INDENT_2}" >> "$KEEPALIVED_CONF"
  344. ;;
  345. MISC_CHECK)
  346. printf '%b%s {\n' "${INDENT_2}" "$check" >> "$KEEPALIVED_CONF"
  347. print_elems_indent "$1" "$INDENT_3" misc_path
  348. printf '%b}\n' "${INDENT_2}" >> "$KEEPALIVED_CONF"
  349. ;;
  350. HTTP_GET | SSL_GET)
  351. printf '%b%s {\n' "${INDENT_2}" "$check" >> "$KEEPALIVED_CONF"
  352. print_elems_indent "$1" "$INDENT_3" connect_timeout \
  353. connect_port nb_get_retry delay_before_retry
  354. # Handle url list
  355. config_list_foreach "$1" url url_list
  356. printf '%b}\n' "${INDENT_2}" >> "$KEEPALIVED_CONF"
  357. ;;
  358. esac
  359. printf '%b}\n' "${INDENT_1}" >> "$KEEPALIVED_CONF"
  360. }
  361. }
  362. real_server_list() {
  363. config_foreach real_server real_server "$1"
  364. }
  365. virtual_server() {
  366. local enabled ipaddr port lb_algo sorry_server_ip sorry_server_port
  367. config_get_bool enabled "$1" enabled 1
  368. [ "$enabled" -eq 1 ] || return 0
  369. config_get ipaddr "$1" ipaddr
  370. [ -z "$ipaddr" ] && return 0
  371. config_get port "$1" port
  372. [ -z "$port" ] && return 0
  373. config_section_open "virtual_server" "$ipaddr $port"
  374. print_elems_indent "$1" "$INDENT_1" fwmark delay_loop \
  375. lb_kind persistence_timeout persistence_granularity \
  376. virtualhost protocol
  377. config_get lb_algo "$1" lb_algo
  378. [ -z "$lb_algo" ] && lb_algo="rr"
  379. modprobe ip_vs_${lb_algo} 1>/dev/null 2>&1
  380. printf '%blb_algo %s\n' "${INDENT_1}" "${lb_algo}" >> "$KEEPALIVED_CONF"
  381. config_get sorry_server_ip "$1" sorry_server_ip
  382. config_get sorry_server_port "$1" sorry_server_port
  383. [ -n "$sorry_server_ip" ] && [ -n "$sorry_server_port" ] && {
  384. printf '%bsorry_server %s %s\n' "${INDENT_1}" "$sorry_server_ip" "$sorry_server_port" >> "$KEEPALIVED_CONF"
  385. }
  386. # Handle real_server list
  387. config_list_foreach "$1" real_server real_server_list
  388. config_section_close
  389. }
  390. process_config() {
  391. local alt_config_file linkbeat_use_polling
  392. rm -f "$KEEPALIVED_CONF"
  393. # First line
  394. printf '! Configuration file for keepalived (autogenerated via init script)\n' > "$KEEPALIVED_CONF"
  395. printf '! Written %s\n\n' "$(date +'%c')" >> "$KEEPALIVED_CONF"
  396. [ -f /etc/config/keepalived ] || return 0
  397. config_load 'keepalived'
  398. config_get alt_config_file globals alt_config_file
  399. # If "alt_config_file" specified, use that instead
  400. [ -n "$alt_config_file" ] && [ -f "$alt_config_file" ] && {
  401. rm -f "$KEEPALIVED_CONF"
  402. # Symlink "alt_config_file" since it's a bit easier and safer
  403. ln -s "$alt_config_file" "$KEEPALIVED_CONF"
  404. return 0
  405. }
  406. config_get_bool linkbeat_use_polling globals linkbeat_use_polling 0
  407. [ "$linkbeat_use_polling" -gt 0 ] && printf 'linkbeat_use_polling\n\n' >> "$KEEPALIVED_CONF"
  408. config_section_open "global_defs"
  409. config_foreach_wrapper globals
  410. config_section_close
  411. config_section_open "static_ipaddress"
  412. config_foreach_wrapper static_ipaddress
  413. config_section_close
  414. config_section_open "static_routes"
  415. config_foreach_wrapper static_routes
  416. config_section_close
  417. config_foreach_wrapper vrrp_script
  418. config_foreach_wrapper vrrp_sync_group
  419. config_foreach_wrapper vrrp_instance
  420. config_foreach_wrapper virtual_server
  421. return 0
  422. }
  423. service_triggers() {
  424. procd_add_reload_trigger "keepalived"
  425. }
  426. reload_service() {
  427. process_config
  428. #SIGHUP is used by keepalived to do init.d reload
  429. procd_send_signal keepalived
  430. }
  431. start_service() {
  432. procd_open_instance
  433. procd_set_param command /usr/sbin/keepalived
  434. procd_append_param command -n # don't daemonize, procd will handle that for us
  435. procd_append_param command -f "$KEEPALIVED_CONF"
  436. process_config
  437. # set auto respawn behavior
  438. procd_set_param respawn
  439. procd_close_instance
  440. }