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.

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