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.

440 lines
11 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. config_section_open() {
  10. local tag=$1
  11. local name=$2
  12. printf "$tag" >> $KEEPALIVED_CONF
  13. [ -n "$name" ] && printf " $name" >> $KEEPALIVED_CONF
  14. printf " {\n" >> $KEEPALIVED_CONF
  15. }
  16. config_section_close() {
  17. printf "}\n\n" >> $KEEPALIVED_CONF
  18. }
  19. config_foreach_wrapper() {
  20. local section=$1
  21. local function=$1
  22. # Convention is that 'function' and 'section' are the same
  23. config_foreach $function $section
  24. }
  25. print_elems_indent() {
  26. local config=$1
  27. shift
  28. local indent=$1
  29. shift
  30. [ -z "$indent" ] && indent="$INDENT_1"
  31. for opt in $*; do
  32. local $opt
  33. local no_val=0
  34. if [ ${opt:0:7} == "no_val_" ]; then
  35. opt=${opt:7}
  36. no_val=1
  37. fi
  38. config_get $opt $config $opt
  39. eval optval=\$$opt
  40. [ -z "$optval" ] && continue
  41. printf "$indent$opt" >> $KEEPALIVED_CONF
  42. [ "$no_val" == "0" ] && {
  43. local words=$(echo "$optval" | wc -w)
  44. if [ $words -gt 1 ]; then
  45. printf " \"$optval\"" >> $KEEPALIVED_CONF
  46. else
  47. printf " $optval" >> $KEEPALIVED_CONF
  48. fi
  49. }
  50. printf "\n" >> $KEEPALIVED_CONF
  51. done
  52. unset optval
  53. }
  54. print_list_indent() {
  55. local lst=$1
  56. local indent=$2
  57. local lst_elems
  58. [ -z "$indent" ] && indent=$INDENT_1
  59. eval lst_elems=\$$lst
  60. [ -z "$lst_elems" ] && return 0
  61. printf "$indent$lst {\n" >> $KEEPALIVED_CONF
  62. for e in $lst_elems; do
  63. [ -n "$eval_item_func" ]
  64. printf "$indent$INDENT_1$e\n" >> $KEEPALIVED_CONF
  65. done
  66. printf "$indent}\n" >> $KEEPALIVED_CONF
  67. }
  68. print_notify() {
  69. local type=$1
  70. shift
  71. local name=$1
  72. shift
  73. for notify in $*; do
  74. printf "$INDENT_1$notify" >> $KEEPALIVED_CONF
  75. notify=$(echo $notify | tr 'a-z' 'A-Z')
  76. printf " \"/bin/busybox env -i ACTION=$notify TYPE=$type NAME=$name /sbin/hotplug-call keepalived\"\n" >> $KEEPALIVED_CONF
  77. done
  78. }
  79. global_defs() {
  80. local linkbeat_use_polling notification_email
  81. config_get alt_config_file $1 alt_config_file
  82. [ -z "$alt_config_file" ] || return 0
  83. config_get_bool linkbeat_use_polling $1 linkbeat_use_polling 0
  84. [ $linkbeat_use_polling -gt 0 ] && printf "linkbeat_use_polling\n\n" >> $KEEPALIVED_CONF
  85. config_get notification_email $1 notification_email
  86. print_list_indent notification_email
  87. print_elems_indent $1 $INDENT_1 notification_email_from smtp_server smtp_connect_timeout \
  88. router_id vrrp_mcast_group4 vrrp_mcast_group6
  89. }
  90. print_ipaddress_indent() {
  91. local section=$1
  92. local curr_ipaddr=$2
  93. local indent=$3
  94. local address device scope name
  95. config_get name $section name
  96. [ "$name" != "$curr_ipaddr" ] && return 0
  97. config_get address $section address
  98. config_get device $section device
  99. config_get scope $section scope
  100. # Default indent
  101. [ -z "$indent" ] && indent=$INDENT_1
  102. # If no address or device exit
  103. [ -z "$address" -o -z "$device" ] && return 0
  104. # Add IP address/netmask and device
  105. printf "$indent$address dev $device" >> $KEEPALIVED_CONF
  106. # Add scope
  107. [ -n "$scope" ] && printf " scope $scope" >> $KEEPALIVED_CONF
  108. printf "\n" >> $KEEPALIVED_CONF
  109. }
  110. static_ipaddress() {
  111. local address
  112. config_get address "$1" address
  113. for a in $address; do
  114. config_foreach print_ipaddress_indent ipaddress $a
  115. done
  116. }
  117. print_route_indent() {
  118. local section=$1
  119. local curr_route=$2
  120. local indent=$3
  121. local name blackhole address src_addr gateway device scope table
  122. config_get name $section name
  123. [ "$name" != "$curr_route" ] && return 0
  124. config_get_bool blackhole $section blackhole 0
  125. config_get address $section address
  126. config_get src_addr $section src_addr
  127. config_get gateway $section gateway
  128. config_get device $section device
  129. config_get table $section table
  130. # If no address exit
  131. [ -z "$address" ] && return 0
  132. # Default indent
  133. [ -z "$indent" ] && indent=$INDENT_1
  134. [ $blackhole -gt 0 ] && {
  135. printf "${indent}blackhole $address\n" >> $KEEPALIVED_CONF
  136. return 0
  137. }
  138. # Add src addr or address
  139. if [ -n "$src_addr" ]; then
  140. printf "${indent}src $src_addr $address" >> $KEEPALIVED_CONF
  141. else
  142. [ -z "$device" ] && return 0
  143. printf "$indent$address" >> $KEEPALIVED_CONF
  144. fi
  145. # Add route/gateway
  146. [ -n "$gateway" ] && printf " via $gateway" >> $KEEPALIVED_CONF
  147. # Add device
  148. printf " dev $device" >> $KEEPALIVED_CONF
  149. # Add scope
  150. [ -n "$scope" ] && printf " scope $scope" >> $KEEPALIVED_CONF
  151. # Add table
  152. [ -n "$table" ] && printf " table $table" >> $KEEPALIVED_CONF
  153. printf "\n" >> $KEEPALIVED_CONF
  154. }
  155. print_track_elem_indent() {
  156. local section=$1
  157. local curr_track_elem=$2
  158. local indent=$3
  159. local script name value
  160. config_get name $section name
  161. [ "$name" != "$curr_track_elem" ] && return 0
  162. config_get value $section value
  163. config_get weight $section weight
  164. [ -z "$value" ] && return 0
  165. printf "$indent$value" >> $KEEPALIVED_CONF
  166. [ -n "$weight" ] && printf " weight $weight" >> $KEEPALIVED_CONF
  167. printf "\n" >> $KEEPALIVED_CONF
  168. }
  169. static_routes() {
  170. local route
  171. config_get route "$1" route
  172. for r in $route; do
  173. config_foreach print_route_indent route $r
  174. done
  175. }
  176. # Count 'vrrp_instance' with the given name ; called by vrrp_instance_check()
  177. vrrp_instance_name_count() {
  178. local name
  179. config_get name $1 name
  180. [ "$name" == "$2" ] && count=$((count + 1))
  181. }
  182. # Check if there's a 'vrrp_instance' section with the given name
  183. vrrp_instance_check() {
  184. local count=0
  185. local name=$1
  186. config_foreach vrrp_instance_name_count vrrp_instance $name
  187. [ $count -gt 0 ] && return 0 || return 1
  188. }
  189. vrrp_sync_group() {
  190. local group name
  191. local valid_group
  192. # No name for group, exit
  193. config_get name $1 name
  194. [ -z "$name" ] && return 0
  195. # No members for group, exit
  196. config_get group $1 group
  197. [ -z "$group" ] && return 0
  198. # Check if we have 'vrrp_instance's defined for
  199. # each member and remove names with not vrrp_instance defined
  200. for m in $group; do
  201. vrrp_instance_check $m && valid_group="$valid_group $m"
  202. done
  203. [ -z "$valid_group" ] && return 0
  204. config_section_open "vrrp_sync_group" "$name"
  205. group="$valid_group"
  206. print_list_indent group
  207. print_elems_indent $1 $INDENT_1 no_val_smtp_alert no_val_global_tracking
  208. print_notify "GROUP" "$name" notify_backup notify_master \
  209. notify_fault notify
  210. config_section_close
  211. }
  212. vrrp_instance() {
  213. local name auth_type auth_pass
  214. config_get name $1 name
  215. [ -z "$name" ] && return 0
  216. config_section_open "vrrp_instance" "$name"
  217. config_get auth_type $1 auth_type
  218. config_get auth_pass $1 auth_pass
  219. [ -n "$auth_type" -a -n "$auth_pass" ] && {
  220. printf "${INDENT_1}authentication {\n" >> $KEEPALIVED_CONF
  221. printf "${INDENT_2}auth_type $auth_type\n" >> $KEEPALIVED_CONF
  222. printf "${INDENT_2}auth_pass $auth_pass\n" >> $KEEPALIVED_CONF
  223. printf "$INDENT_1}\n" >> $KEEPALIVED_CONF
  224. }
  225. print_elems_indent $1 $INDENT_1 use_vmac state interface \
  226. mcast_src_ip unicast_src_ip virtual_router_id version priority \
  227. advert_int preempt_delay debug \
  228. lvs_sync_daemon_interface garp_master_delay garp_master_refresh \
  229. garp_master_repeat garp_master_refresh_repeat \
  230. no_val_vmac_xmit_base no_val_native_ipv6 no_val_accept \
  231. no_val_dont_track_primary no_val_smtp_alert no_val_nopreempt
  232. print_notify "INSTANCE" "$name" notify_backup notify_master \
  233. notify_fault notify_stop notify
  234. # Handle virtual_ipaddress & virtual_ipaddress_excluded lists
  235. for opt in virtual_ipaddress virtual_ipaddress_excluded; do
  236. config_get $opt $1 $opt
  237. eval optval=\$$opt
  238. [ -z "$optval" ] && continue
  239. printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF
  240. for a in $optval; do
  241. config_foreach print_ipaddress_indent ipaddress $a $INDENT_2
  242. done
  243. printf "$INDENT_1}\n" >> $KEEPALIVED_CONF
  244. done
  245. # Handle virtual_routes
  246. for opt in virtual_routes; do
  247. config_get $opt $1 $opt
  248. eval optval=\$$opt
  249. [ -z "$optval" ] && continue
  250. printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF
  251. for r in $optval; do
  252. config_foreach print_route_indent route $r $INDENT_2
  253. done
  254. printf "$INDENT_1}\n" >> $KEEPALIVED_CONF
  255. done
  256. # Handle track_script lists
  257. for opt in track_script; do
  258. config_get $opt $1 $opt
  259. eval optval=\$$opt
  260. [ -z "$optval" ] && continue
  261. printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF
  262. for t in $optval; do
  263. printf "$INDENT_2$optval\n" >> $KEEPALIVED_CONF
  264. done
  265. printf "$INDENT_1}\n" >> $KEEPALIVED_CONF
  266. done
  267. # Handle track_interface lists
  268. for opt in track_interface; do
  269. config_get $opt $1 $opt
  270. eval optval=\$$opt
  271. [ -z "$optval" ] && continue
  272. printf "$INDENT_1$opt {\n" >> $KEEPALIVED_CONF
  273. for t in $optval; do
  274. config_foreach print_track_elem_indent track_interface $t $INDENT_2
  275. done
  276. printf "$INDENT_1}\n" >> $KEEPALIVED_CONF
  277. done
  278. # Handle simple lists of strings (with no spaces in between)
  279. for opt in unicast_peer; do
  280. config_get $opt $1 $opt
  281. print_list_indent $opt
  282. done
  283. unset optval
  284. config_section_close
  285. }
  286. vrrp_script() {
  287. local name
  288. config_get name $1 name
  289. [ -z "$name" ] && return 0
  290. config_section_open "vrrp_script" "$name"
  291. print_elems_indent $1 $INDENT_1 script interval weight fall rise
  292. config_section_close
  293. }
  294. process_config() {
  295. local alt_config_file
  296. rm -f $KEEPALIVED_CONF
  297. # First line
  298. printf "! Configuration File for keepalived (autogenerated via init script)\n\n" > $KEEPALIVED_CONF
  299. [ -f /etc/config/keepalived ] || return 0
  300. config_load 'keepalived'
  301. config_section_open "global_defs"
  302. config_foreach_wrapper global_defs
  303. config_section_close
  304. # If "alt_config_file" specified, use that instead
  305. [ -n "$alt_config_file" ] && [ -f "$alt_config_file" ] && {
  306. rm -f $KEEPALIVED_CONF
  307. # Symlink "alt_config_file" since it's a bit easier and safer
  308. ln -s $alt_config_file $KEEPALIVED_CONF
  309. return 0
  310. }
  311. config_section_open "static_ipaddress"
  312. config_foreach_wrapper static_ipaddress
  313. config_section_close
  314. config_section_open "static_routes"
  315. config_foreach_wrapper static_routes
  316. config_section_close
  317. config_foreach_wrapper vrrp_script
  318. config_foreach_wrapper vrrp_sync_group
  319. config_foreach_wrapper vrrp_instance
  320. return 0
  321. }
  322. service_running() {
  323. pgrep -x /usr/sbin/keepalived &> /dev/null
  324. }
  325. conf_md5() {
  326. echo "$(md5sum $KEEPALIVED_CONF | awk '{print $1}')"
  327. }
  328. reload_service() {
  329. local cur_md5="$(conf_md5)"
  330. running && {
  331. process_config
  332. # Return without performing the reload if config
  333. # file md5sum has not changed
  334. local new_md5="$(conf_md5)"
  335. [ "$new_md5" == "$cur_md5" ] && return 0;
  336. # SIGHUP is used by keepalived to do init.d reload
  337. # Get the oldest process (assumption is that it's the parent process)
  338. PID=$(pgrep -o /usr/sbin/keepalived)
  339. kill -SIGHUP $PID
  340. return 0
  341. }
  342. return 1
  343. }
  344. start_service() {
  345. procd_open_instance
  346. procd_set_param command /usr/sbin/keepalived
  347. procd_append_param command -n # don't daemonize, procd will handle that for us
  348. procd_append_param command -f "$KEEPALIVED_CONF"
  349. process_config
  350. # set auto respawn behavior
  351. procd_set_param respawn
  352. procd_close_instance
  353. }