· 8 years ago · Dec 21, 2017, 11:02 AM
1#!/bin/sh
2#
3# $Id: awsvip.in,v 1.24 2006/08/09 13:01:54 lars Exp $
4#
5# OCF Resource Agent compliant awsvip script.
6#
7# Based on work by Tuomo Soini, ported to the OCF RA API by Lars
8# Marowsky-Brée. Implements Cluster Alias IP functionality too.
9#
10# Cluster Alias IP cleanup, fixes and testing by Michael Schwartzkopff
11#
12#
13# Copyright (c) 2003 Tuomo Soini
14# Copyright (c) 2004-2006 SUSE LINUX AG, Lars Marowsky-Brée
15# All Rights Reserved.
16#
17# This program is free software; you can redistribute it and/or modify
18# it under the terms of version 2 of the GNU General Public License as
19# published by the Free Software Foundation.
20#
21# This program is distributed in the hope that it would be useful, but
22# WITHOUT ANY WARRANTY; without even the implied warranty of
23# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24#
25# Further, this software is distributed without any warranty that it is
26# free of the rightful claim of any third person regarding infringement
27# or the like. Any license provided herein, whether implied or
28# otherwise, applies only to this software file. Patent licenses, if
29# any, provided herein do not apply to combinations of this program with
30# other software, or any other product whatsoever.
31#
32# You should have received a copy of the GNU General Public License
33# along with this program; if not, write the Free Software Foundation,
34# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
35#
36#
37
38
39# TODO:
40# - There ought to be an ocf_run_cmd function which does all logging,
41# timeout handling etc for us
42# - Make this the standard IP address agent on Linux; the other
43# platforms simply should ignore the additional parameters OR can use
44# the legacy heartbeat resource script...
45# - Check LVS <-> clusterip incompatibilities.
46#
47# OCF parameters are as below
48# OCF_RESKEY_ip
49# OCF_RESKEY_broadcast
50# OCF_RESKEY_nic
51# OCF_RESKEY_cidr_netmask
52# OCF_RESKEY_iflabel
53# OCF_RESKEY_mac
54# OCF_RESKEY_clusterip_hash
55# OCF_RESKEY_arp_interval
56# OCF_RESKEY_arp_count
57# OCF_RESKEY_arp_bg
58# OCF_RESKEY_arp_mac
59#
60# OCF_RESKEY_CRM_meta_clone
61# OCF_RESKEY_CRM_meta_clone_max
62
63
64#######################################################################
65# Initialization:
66
67: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
68. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
69. ${OCF_FUNCTIONS_DIR}/findif.sh
70
71# Defaults
72OCF_RESKEY_lvs_support_default=false
73OCF_RESKEY_lvs_ipv6_addrlabel_default=false
74OCF_RESKEY_lvs_ipv6_addrlabel_value_default=99
75OCF_RESKEY_clusterip_hash_default="sourceip-sourceport"
76OCF_RESKEY_unique_clone_address_default=false
77OCF_RESKEY_arp_interval_default=200
78OCF_RESKEY_arp_count_default=5
79OCF_RESKEY_arp_bg_default=true
80OCF_RESKEY_arp_mac_default="ffffffffffff"
81
82: ${OCF_RESKEY_lvs_support=${OCF_RESKEY_lvs_support_default}}
83: ${OCF_RESKEY_lvs_ipv6_addrlabel=${OCF_RESKEY_lvs_ipv6_addrlabel_default}}
84: ${OCF_RESKEY_lvs_ipv6_addrlabel_value=${OCF_RESKEY_lvs_ipv6_addrlabel_value_default}}
85: ${OCF_RESKEY_clusterip_hash=${OCF_RESKEY_clusterip_hash_default}}
86: ${OCF_RESKEY_unique_clone_address=${OCF_RESKEY_unique_clone_address_default}}
87: ${OCF_RESKEY_arp_interval=${OCF_RESKEY_arp_interval_default}}
88: ${OCF_RESKEY_arp_count=${OCF_RESKEY_arp_count_default}}
89: ${OCF_RESKEY_arp_bg=${OCF_RESKEY_arp_bg_default}}
90: ${OCF_RESKEY_arp_mac=${OCF_RESKEY_arp_mac_default}}
91#######################################################################
92
93SENDARP=$HA_BIN/send_arp
94SENDUA=$HA_BIN/send_ua
95FINDIF=findif
96VLDIR=$HA_RSCTMP
97SENDARPPIDDIR=$HA_RSCTMP
98CIP_lockfile=$HA_RSCTMP/awsvip-CIP-${OCF_RESKEY_ip}
99
100#######################################################################
101
102meta_data() {
103 cat <<END
104<?xml version="1.0"?>
105<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
106<resource-agent name="awsvip">
107<version>1.0</version>
108
109<longdesc lang="en">
110This Linux-specific resource manages IP alias IP addresses.
111It can add an IP alias, or remove one.
112In addition, it can implement Cluster Alias IP functionality
113if invoked as a clone resource.
114
115If used as a clone, you should explicitly set clone-node-max >= 2,
116and/or clone-max < number of nodes. In case of node failure,
117clone instances need to be re-allocated on surviving nodes.
118This would not be possible if there is already an instance on those nodes,
119and clone-node-max=1 (which is the default).
120</longdesc>
121
122<shortdesc lang="en">Manages virtual IPv4 and IPv6 addresses (Linux specific version)</shortdesc>
123
124<parameters>
125<parameter name="ip" unique="1" required="1">
126<longdesc lang="en">
127The IPv4 (dotted quad notation) or IPv6 address (colon hexadecimal notation)
128example IPv4 "192.168.1.1".
129example IPv6 "2001:db8:DC28:0:0:FC57:D4C8:1FFF".
130</longdesc>
131<shortdesc lang="en">IPv4 or IPv6 address</shortdesc>
132<content type="string" default="" />
133</parameter>
134<parameter name="nic" unique="0">
135<longdesc lang="en">
136The base network interface on which the IP address will be brought
137online.
138If left empty, the script will try and determine this from the
139routing table.
140
141Do NOT specify an alias interface in the form eth0:1 or anything here;
142rather, specify the base interface only.
143If you want a label, see the iflabel parameter.
144
145Prerequisite:
146
147There must be at least one static IP address, which is not managed by
148the cluster, assigned to the network interface.
149If you can not assign any static IP address on the interface,
150modify this kernel parameter:
151
152sysctl -w net.ipv4.conf.all.promote_secondaries=1 # (or per device)
153</longdesc>
154<shortdesc lang="en">Network interface</shortdesc>
155<content type="string"/>
156</parameter>
157
158<parameter name="cidr_netmask">
159<longdesc lang="en">
160The netmask for the interface in CIDR format
161(e.g., 24 and not 255.255.255.0)
162
163If unspecified, the script will also try to determine this from the
164routing table.
165</longdesc>
166<shortdesc lang="en">CIDR netmask</shortdesc>
167<content type="string" default=""/>
168</parameter>
169
170<parameter name="broadcast">
171<longdesc lang="en">
172Broadcast address associated with the IP. If left empty, the script will
173determine this from the netmask.
174</longdesc>
175<shortdesc lang="en">Broadcast address</shortdesc>
176<content type="string" default=""/>
177</parameter>
178
179<parameter name="iflabel">
180<longdesc lang="en">
181You can specify an additional label for your IP address here.
182This label is appended to your interface name.
183
184A label can be specified in nic parameter but it is deprecated.
185If a label is specified in nic name, this parameter has no effect.
186</longdesc>
187<shortdesc lang="en">Interface label</shortdesc>
188<content type="string" default=""/>
189</parameter>
190
191<parameter name="lvs_support">
192<longdesc lang="en">
193Enable support for LVS Direct Routing configurations. In case a IP
194address is stopped, only move it to the loopback device to allow the
195local node to continue to service requests, but no longer advertise it
196on the network.
197
198Notes for IPv6:
199It is not necessary to enable this option on IPv6.
200Instead, enable 'lvs_ipv6_addrlabel' option for LVS-DR usage on IPv6.
201</longdesc>
202<shortdesc lang="en">Enable support for LVS DR</shortdesc>
203<content type="boolean" default="${OCF_RESKEY_lvs_support_default}"/>
204</parameter>
205
206<parameter name="lvs_ipv6_addrlabel">
207<longdesc lang="en">
208Enable adding IPv6 address label so IPv6 traffic originating from
209the address's interface does not use this address as the source.
210This is necessary for LVS-DR health checks to realservers to work. Without it,
211the most recently added IPv6 address (probably the address added by awsvip)
212will be used as the source address for IPv6 traffic from that interface and
213since that address exists on loopback on the realservers, the realserver
214response to pings/connections will never leave its loopback.
215See RFC3484 for the detail of the source address selection.
216
217See also 'lvs_ipv6_addrlabel_value' parameter.
218</longdesc>
219<shortdesc lang="en">Enable adding IPv6 address label.</shortdesc>
220<content type="boolean" default="${OCF_RESKEY_lvs_ipv6_addrlabel_default}"/>
221</parameter>
222
223<parameter name="lvs_ipv6_addrlabel_value">
224<longdesc lang="en">
225Specify IPv6 address label value used when 'lvs_ipv6_addrlabel' is enabled.
226The value should be an unused label in the policy table
227which is shown by 'ip addrlabel list' command.
228You would rarely need to change this parameter.
229</longdesc>
230<shortdesc lang="en">IPv6 address label value.</shortdesc>
231<content type="integer" default="${OCF_RESKEY_lvs_ipv6_addrlabel_value_default}"/>
232</parameter>
233
234<parameter name="mac">
235<longdesc lang="en">
236Set the interface MAC address explicitly. Currently only used in case of
237the Cluster IP Alias. Leave empty to chose automatically.
238
239</longdesc>
240<shortdesc lang="en">Cluster IP MAC address</shortdesc>
241<content type="string" default=""/>
242</parameter>
243
244<parameter name="clusterip_hash">
245<longdesc lang="en">
246Specify the hashing algorithm used for the Cluster IP functionality.
247
248</longdesc>
249<shortdesc lang="en">Cluster IP hashing function</shortdesc>
250<content type="string" default="${OCF_RESKEY_clusterip_hash_default}"/>
251</parameter>
252
253<parameter name="unique_clone_address">
254<longdesc lang="en">
255If true, add the clone ID to the supplied value of IP to create
256a unique address to manage
257</longdesc>
258<shortdesc lang="en">Create a unique address for cloned instances</shortdesc>
259<content type="boolean" default="${OCF_RESKEY_unique_clone_address_default}"/>
260</parameter>
261
262<parameter name="arp_interval">
263<longdesc lang="en">
264Specify the interval between unsolicited ARP packets in milliseconds.
265</longdesc>
266<shortdesc lang="en">ARP packet interval in ms</shortdesc>
267<content type="integer" default="${OCF_RESKEY_arp_interval_default}"/>
268</parameter>
269
270<parameter name="arp_count">
271<longdesc lang="en">
272Number of unsolicited ARP packets to send.
273</longdesc>
274<shortdesc lang="en">ARP packet count</shortdesc>
275<content type="integer" default="${OCF_RESKEY_arp_count_default}"/>
276</parameter>
277
278<parameter name="arp_bg">
279<longdesc lang="en">
280Whether or not to send the ARP packets in the background.
281</longdesc>
282<shortdesc lang="en">ARP from background</shortdesc>
283<content type="string" default="${OCF_RESKEY_arp_bg_default}"/>
284</parameter>
285
286<parameter name="arp_mac">
287<longdesc lang="en">
288MAC address to send the ARP packets to.
289
290You really shouldn't be touching this.
291
292</longdesc>
293<shortdesc lang="en">ARP MAC</shortdesc>
294<content type="string" default="${OCF_RESKEY_arp_mac_default}"/>
295</parameter>
296
297<parameter name="arp_sender">
298<longdesc lang="en">
299The program to send ARP packets with on start. For infiniband
300interfaces, default is ipoibarping. If ipoibarping is not
301available, set this to send_arp.
302</longdesc>
303<shortdesc lang="en">ARP sender</shortdesc>
304<content type="string" default=""/>
305</parameter>
306
307<parameter name="flush_routes">
308<longdesc lang="en">
309Flush the routing table on stop. This is for
310applications which use the cluster IP address
311and which run on the same physical host that the
312IP address lives on. The Linux kernel may force that
313application to take a shortcut to the local loopback
314interface, instead of the interface the address
315is really bound to. Under those circumstances, an
316application may, somewhat unexpectedly, continue
317to use connections for some time even after the
318IP address is deconfigured. Set this parameter in
319order to immediately disable said shortcut when the
320IP address goes away.
321</longdesc>
322<shortdesc lang="en">Flush kernel routing table on stop</shortdesc>
323<content type="boolean" default="false"/>
324</parameter>
325
326</parameters>
327<actions>
328<action name="start" timeout="20s" />
329<action name="stop" timeout="20s" />
330<action name="status" depth="0" timeout="20s" interval="10s" />
331<action name="monitor" depth="0" timeout="20s" interval="10s" />
332<action name="meta-data" timeout="5s" />
333<action name="validate-all" timeout="20s" />
334</actions>
335</resource-agent>
336END
337
338 exit $OCF_SUCCESS
339}
340
341ip_init() {
342 local rc
343
344 if [ X`uname -s` != "XLinux" ]; then
345 ocf_exit_reason "awsvip only supported Linux."
346 exit $OCF_ERR_INSTALLED
347 fi
348
349 if [ X"$OCF_RESKEY_ip" = "X" ]; then
350 ocf_exit_reason "IP address (the ip parameter) is mandatory"
351 exit $OCF_ERR_CONFIGURED
352 fi
353
354 if
355 case $__OCF_ACTION in
356 start|stop) ocf_is_root;;
357 *) true;;
358 esac
359 then
360 : YAY!
361 else
362 ocf_exit_reason "You must be root for $__OCF_ACTION operation."
363 exit $OCF_ERR_PERM
364 fi
365
366 BASEIP="$OCF_RESKEY_ip"
367 BRDCAST="$OCF_RESKEY_broadcast"
368 NIC="$OCF_RESKEY_nic"
369 # Note: We had a version out there for a while which used
370 # netmask instead of cidr_netmask. Don't remove this aliasing code!
371 if
372 [ ! -z "$OCF_RESKEY_netmask" -a -z "$OCF_RESKEY_cidr_netmask" ]
373 then
374 OCF_RESKEY_cidr_netmask=$OCF_RESKEY_netmask
375 export OCF_RESKEY_cidr_netmask
376 fi
377 NETMASK="$OCF_RESKEY_cidr_netmask"
378 IFLABEL="$OCF_RESKEY_iflabel"
379 IF_MAC="$OCF_RESKEY_mac"
380
381 IP_INC_GLOBAL=${OCF_RESKEY_CRM_meta_clone_max:-1}
382 IP_INC_NO=`expr ${OCF_RESKEY_CRM_meta_clone:-0} + 1`
383
384 if ocf_is_true ${OCF_RESKEY_lvs_support} && [ $IP_INC_GLOBAL -gt 1 ]; then
385 ocf_exit_reason "LVS and load sharing do not go together well"
386 exit $OCF_ERR_CONFIGURED
387 fi
388
389 if ocf_is_decimal "$IP_INC_GLOBAL" && [ $IP_INC_GLOBAL -gt 0 ]; then
390 :
391 else
392 ocf_exit_reason "Invalid meta-attribute clone_max [$IP_INC_GLOBAL], should be positive integer"
393 exit $OCF_ERR_CONFIGURED
394 fi
395
396 echo $OCF_RESKEY_ip | grep -qs ":"
397 if [ $? -ne 0 ];then
398 FAMILY=inet
399 if ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
400 ocf_exit_reason "IPv4 does not support lvs_ipv6_addrlabel"
401 exit $OCF_ERR_CONFIGURED
402 fi
403 else
404 FAMILY=inet6
405 if ocf_is_true $OCF_RESKEY_lvs_support ;then
406 ocf_exit_reason "The IPv6 does not support lvs_support"
407 exit $OCF_ERR_CONFIGURED
408 fi
409 if ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
410 if ocf_is_decimal "$OCF_RESKEY_lvs_ipv6_addrlabel_value" && [ $OCF_RESKEY_lvs_ipv6_addrlabel_value -ge 0 ]; then
411 :
412 else
413 ocf_exit_reason "Invalid lvs_ipv6_addrlabel_value [$OCF_RESKEY_lvs_ipv6_addrlabel_value], should be positive integer"
414 exit $OCF_ERR_CONFIGURED
415 fi
416 fi
417 fi
418
419 # support nic:iflabel format in nic parameter
420 case $NIC in
421 *:*)
422 IFLABEL=`echo $NIC | sed 's/[^:]*://'`
423 NIC=`echo $NIC | sed 's/:.*//'`
424 # only the base name should be passed to findif
425 OCF_RESKEY_nic=$NIC
426 ;;
427 esac
428
429 # $FINDIF takes its parameters from the environment
430 #
431 NICINFO=`$FINDIF`
432 rc=$?
433 if
434 [ $rc -eq 0 ]
435 then
436 NICINFO=`echo "$NICINFO" | sed -e 's/netmask\ //;s/broadcast\ //'`
437 NIC=`echo "$NICINFO" | cut -d" " -f1`
438 NETMASK=`echo "$NICINFO" | cut -d" " -f2`
439 BRDCAST=`echo "$NICINFO" | cut -d" " -f3`
440 else
441 # findif couldn't find the interface
442 if ocf_is_probe; then
443 ocf_log info "[$FINDIF] failed"
444 exit $OCF_NOT_RUNNING
445 elif [ "$__OCF_ACTION" = stop ]; then
446 ocf_log warn "[$FINDIF] failed"
447 exit $OCF_SUCCESS
448 else
449 ocf_log err "[$FINDIF] failed"
450 exit $rc
451 fi
452 fi
453
454 SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$OCF_RESKEY_ip"
455
456 if [ -n "$IFLABEL" ]; then
457 IFLABEL=${NIC}:${IFLABEL}
458 fi
459
460 if [ "$IP_INC_GLOBAL" -gt 1 ] && ! ocf_is_true "$OCF_RESKEY_unique_clone_address"; then
461 IP_CIP="yes"
462 IP_CIP_HASH="${OCF_RESKEY_clusterip_hash}"
463 if [ -z "$IF_MAC" ]; then
464 # Choose a MAC
465 # 1. Concatenate some input together
466 # 2. This doesn't need to be a cryptographically
467 # secure hash.
468 # 3. Drop everything after the first 6 octets (12 chars)
469 # 4. Delimit the octets with ':'
470 # 5. Make sure the first octet is odd,
471 # so the result is a multicast MAC
472 IF_MAC=`echo $OCF_RESKEY_ip $NETMASK $BRDCAST | \
473 md5sum | \
474 sed -e 's#\(............\).*#\1#' \
475 -e 's#..#&:#g; s#:$##' \
476 -e 's#^\(.\)[02468aAcCeE]#\11#'`
477 fi
478 IP_CIP_FILE="/proc/net/ipt_CLUSTERIP/$OCF_RESKEY_ip"
479 fi
480}
481
482#
483# Find out which interfaces serve the given IP address and netmask.
484# The arguments are an IP address and a netmask.
485# Its output are interface names devided by spaces (e.g., "eth0 eth1").
486#
487find_interface() {
488 local ipaddr="$1"
489 local netmask="$2"
490
491 #
492 # List interfaces but exclude FreeS/WAN ipsecN virtual interfaces
493 #
494 local iface="`$IP2UTIL -o -f $FAMILY addr show \
495 | grep "\ $ipaddr/$netmask" \
496 | cut -d ' ' -f2 \
497 | grep -v '^ipsec[0-9][0-9]*$'`"
498
499 echo "$iface"
500 return 0
501}
502
503#
504# Delete an interface
505#
506delete_interface () {
507 ipaddr="$1"
508 iface="$2"
509 netmask="$3"
510
511 CMD="$IP2UTIL -f $FAMILY addr delete $ipaddr/$netmask dev $iface"
512
513 ocf_run $CMD || return $OCF_ERR_GENERIC
514
515 if ocf_is_true $OCF_RESKEY_flush_routes; then
516 ocf_run $IP2UTIL route flush cache
517 fi
518
519 if [ "$FAMILY" = "inet6" ] && ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
520 delete_ipv6_addrlabel $ipaddr
521 fi
522
523 return $OCF_SUCCESS
524}
525
526#
527# Add an interface
528#
529add_interface () {
530 local cmd msg ipaddr netmask broadcast iface label
531
532 ipaddr="$1"
533 netmask="$2"
534 broadcast="$3"
535 iface="$4"
536 label="$5"
537
538 if [ "$FAMILY" = "inet6" ] && ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
539 add_ipv6_addrlabel $ipaddr
540 fi
541
542 hostname=`hostname`
543 eni=`aws ec2 describe-instances --filter Name=tag:Name,Values=$hostname --output text|awk -F"\t" '$1=="NETWORKINTERFACES" {print $4}'`
544 cmd="$IP2UTIL -f $FAMILY addr add $ipaddr/$netmask dev $iface"
545 msg="Adding $FAMILY address $ipaddr/$netmask to device $iface"
546 if [ "$broadcast" != "none" ]; then
547 cmd="$IP2UTIL -f $FAMILY addr add $ipaddr/$netmask brd $broadcast dev $iface"
548 msg="Adding $FAMILY address $ipaddr/$netmask with broadcast address $broadcast to device $iface"
549 fi
550
551 if [ ! -z "$label" ]; then
552 cmd="$cmd label $label"
553 msg="${msg} (with label $label)"
554 fi
555
556 ocf_log info "$msg"
557 # Move IP via AWS prior to calling ocf_run
558 aws ec2 assign-private-ip-addresses --network-interface-id $eni --allow-reassignment --private-ip-addresses $ipaddr || return $OCF_ERR_GENERIC
559 ocf_run $cmd || return $OCF_ERR_GENERIC
560
561 msg="Bringing device $iface up"
562 cmd="$IP2UTIL link set $iface up"
563 ocf_log info "$msg"
564 ocf_run $cmd || return $OCF_ERR_GENERIC
565
566 return $OCF_SUCCESS
567}
568
569#
570# Delete a route
571#
572delete_route () {
573 prefix="$1"
574 iface="$2"
575
576 CMD="$IP2UTIL route delete $prefix dev $iface"
577
578 ocf_log info "$CMD"
579 $CMD
580
581 return $?
582}
583
584# On Linux systems the (hidden) loopback interface may
585# conflict with the requested IP address. If so, this
586# unoriginal code will remove the offending loopback address
587# and save it in VLDIR so it can be added back in later
588# when the IPaddr is released.
589#
590# TODO: This is very ugly and should be controlled by an additional
591# instance parameter. Or even: multi-state, with the IP only being
592# "active" on the master!?
593#
594remove_conflicting_loopback() {
595 ipaddr="$1"
596 netmask="$2"
597 broadcast="$3"
598 ifname="$4"
599
600 ocf_log info "Removing conflicting loopback $ifname."
601 if
602 echo "$ipaddr $netmask $broadcast $ifname" > "$VLDIR/$ipaddr"
603 then
604 : Saved loopback information in $VLDIR/$ipaddr
605 else
606 ocf_log err "Could not save conflicting loopback $ifname." \
607 "it will not be restored."
608 fi
609 delete_interface "$ipaddr" "$ifname" "$netmask"
610 # Forcibly remove the route (if it exists) to the loopback.
611 delete_route "$ipaddr" "$ifname"
612}
613
614#
615# On Linux systems the (hidden) loopback interface may
616# need to be restored if it has been taken down previously
617# by remove_conflicting_loopback()
618#
619restore_loopback() {
620 ipaddr="$1"
621
622 if [ -s "$VLDIR/$ipaddr" ]; then
623 ifinfo=`cat "$VLDIR/$ipaddr"`
624 ocf_log info "Restoring loopback IP Address " \
625 "$ifinfo."
626 add_interface $ifinfo
627 rm -f "$VLDIR/$ipaddr"
628 fi
629}
630
631add_ipv6_addrlabel() {
632 local cmd ipaddr value
633 ipaddr="$1"
634 value="$OCF_RESKEY_lvs_ipv6_addrlabel_value"
635
636 cmd="$IP2UTIL addrlabel add prefix $ipaddr label $value"
637 ocf_log info "Adding IPv6 address label prefix $ipaddr label $value"
638 ocf_run $cmd || ocf_log warn "$cmd failed."
639}
640
641delete_ipv6_addrlabel() {
642 local cmd ipaddr value
643 ipaddr="$1"
644 value="$OCF_RESKEY_lvs_ipv6_addrlabel_value"
645
646 cmd="$IP2UTIL addrlabel del prefix $ipaddr label $value"
647 ocf_run $cmd # an error can be ignored
648}
649
650is_infiniband() {
651 $IP2UTIL link show $NIC | grep link/infiniband >/dev/null
652}
653
654#
655# Run send_arp to note peers about new mac address
656#
657run_send_arp() {
658 ARGS="-i $OCF_RESKEY_arp_interval -r $OCF_RESKEY_arp_count -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip auto not_used not_used"
659 if [ "x$IP_CIP" = "xyes" ] ; then
660 if [ x = "x$IF_MAC" ] ; then
661 MY_MAC=auto
662 else
663 MY_MAC=`echo ${IF_MAC} | sed -e 's/://g'`
664 fi
665 ARGS="-i $OCF_RESKEY_arp_interval -r $OCF_RESKEY_arp_count -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip $MY_MAC not_used not_used"
666 fi
667 ocf_log info "$SENDARP $ARGS"
668 if ocf_is_true $OCF_RESKEY_arp_bg; then
669 ($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps")& >&2
670 else
671 $SENDARP $ARGS || ocf_log err "Could not send gratuitous arps"
672 fi
673}
674
675#
676# Run send_ua to note send ICMPv6 Unsolicited Neighbor Advertisements.
677#
678run_send_ua() {
679 local i
680 # Wait until the allocated IPv6 address gets ready by checking
681 # "tentative" flag is disappeared, otherwise send_ua can not
682 # send the unsolicited advertisement requests.
683 for i in 1 2 3 4 5; do
684 $IP2UTIL -o -f $FAMILY addr show dev $NIC \
685 | grep -q -e "$OCF_RESKEY_ip/$NETMASK .* tentative"
686 [ $? -ne 0 ] && break
687 if [ $i -eq 5 ]; then
688 ocf_log warn "$OCF_RESKEY_ip still has 'tentative' status. (ignored)"
689 break
690 fi
691 sleep 1
692 done
693 ARGS="-i $OCF_RESKEY_arp_interval -c $OCF_RESKEY_arp_count $OCF_RESKEY_ip $NETMASK $NIC"
694 ocf_log info "$SENDUA $ARGS"
695 $SENDUA $ARGS || ocf_log err "Could not send ICMPv6 Unsolicited Neighbor Advertisements."
696}
697
698#
699# Run ipoibarping to note peers about new Infiniband address
700#
701run_send_ib_arp() {
702 ARGS="-q -c $OCF_RESKEY_arp_count -U -I $NIC $OCF_RESKEY_ip"
703 ocf_log info "ipoibarping $ARGS"
704 if ocf_is_true $OCF_RESKEY_arp_bg; then
705 (ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps")& >&2
706 else
707 ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps"
708 fi
709}
710
711# Do we already serve this IP address on the given $NIC?
712#
713# returns:
714# ok = served (for CIP: + hash bucket)
715# partial = served and no hash bucket (CIP only)
716# partial2 = served and no CIP iptables rule
717# no = nothing
718#
719ip_served() {
720 if [ -z "$NIC" ]; then # no nic found or specified
721 echo "no"
722 return 0
723 fi
724
725 cur_nic="`find_interface $OCF_RESKEY_ip $NETMASK`"
726
727 if [ -z "$cur_nic" ]; then
728 echo "no"
729 return 0
730 fi
731
732 if [ -z "$IP_CIP" ]; then
733 for i in $cur_nic; do
734 # only mark as served when on the same interfaces as $NIC
735 [ "$i" = "$NIC" ] || continue
736 echo "ok"
737 return 0
738 done
739 # There used to be logic here to pretend "not served",
740 # if ${OCF_RESKEY_lvs_support} was enabled, and the IP was
741 # found active on "lo*" only. With lvs_support on, you should
742 # have NIC != lo, so thats already filtered
743 # by the continue above.
744
745 echo "no"
746 return 0
747 fi
748
749 # Special handling for the CIP:
750 if [ ! -e $IP_CIP_FILE ]; then
751 echo "partial2"
752 return 0
753 fi
754 if egrep -q "(^|,)${IP_INC_NO}(,|$)" $IP_CIP_FILE ; then
755 echo "ok"
756 return 0
757 else
758 echo "partial"
759 return 0
760 fi
761
762 exit $OCF_ERR_GENERIC
763}
764
765#######################################################################
766
767ip_usage() {
768 cat <<END
769usage: $0 {start|stop|status|monitor|validate-all|meta-data}
770
771Expects to have a fully populated OCF RA-compliant environment set.
772END
773}
774
775ip_start() {
776 if [ -z "$NIC" ]; then
777 ocf_exit_reason "No nic found or specified"
778 exit $OCF_ERR_CONFIGURED
779 fi
780
781 if [ -n "$IP_CIP" ]; then
782 # Cluster IPs need special processing when the first bucket
783 # is added to the node... take a lock to make sure only one
784 # process executes that code
785 ocf_take_lock $CIP_lockfile
786 ocf_release_lock_on_exit $CIP_lockfile
787 fi
788
789 #
790 # Do we already service this IP address on $NIC?
791 #
792 local ip_status=`ip_served`
793
794 if [ "$ip_status" = "ok" ]; then
795 exit $OCF_SUCCESS
796 fi
797
798 if [ -n "$IP_CIP" ] && [ $ip_status = "no" ] || [ $ip_status = "partial2" ]; then
799 $MODPROBE ip_conntrack
800 $IPTABLES -I INPUT -d $OCF_RESKEY_ip -i $NIC -j CLUSTERIP \
801 --new \
802 --clustermac $IF_MAC \
803 --total-nodes $IP_INC_GLOBAL \
804 --local-node $IP_INC_NO \
805 --hashmode $IP_CIP_HASH
806 if [ $? -ne 0 ]; then
807 ocf_exit_reason "iptables failed"
808 exit $OCF_ERR_GENERIC
809 fi
810 fi
811
812 if [ -n "$IP_CIP" ] && [ $ip_status = "partial" ]; then
813 echo "+$IP_INC_NO" >$IP_CIP_FILE
814 fi
815
816 if [ "$ip_status" = "no" ]; then
817 if ocf_is_true ${OCF_RESKEY_lvs_support}; then
818 for i in `find_interface $OCF_RESKEY_ip 32`; do
819 case $i in
820 lo*)
821 remove_conflicting_loopback $OCF_RESKEY_ip 32 255.255.255.255 lo
822 ;;
823 esac
824 done
825 fi
826
827 add_interface $OCF_RESKEY_ip $NETMASK ${BRDCAST:-none} $NIC $IFLABEL
828
829 if [ $? -ne 0 ]; then
830 ocf_exit_reason "$CMD failed."
831 exit $OCF_ERR_GENERIC
832 fi
833 fi
834
835 case $NIC in
836 lo*)
837 : no need to run send_arp on loopback
838 ;;
839 *)
840 if [ $FAMILY = "inet" ];then
841 $ARP_SEND_FUN
842 else
843 if [ -x $SENDUA ]; then
844 run_send_ua
845 fi
846 fi
847 ;;
848 esac
849 exit $OCF_SUCCESS
850}
851
852ip_stop() {
853 local ip_del_if="yes"
854 if [ -n "$IP_CIP" ]; then
855 # Cluster IPs need special processing when the last bucket
856 # is removed from the node... take a lock to make sure only one
857 # process executes that code
858 ocf_take_lock $CIP_lockfile
859 ocf_release_lock_on_exit $CIP_lockfile
860 fi
861
862 if [ -f "$SENDARPPIDFILE" ] ; then
863 kill `cat "$SENDARPPIDFILE"`
864 if [ $? -ne 0 ]; then
865 ocf_log warn "Could not kill previously running send_arp for $OCF_RESKEY_ip"
866 else
867 ocf_log info "killed previously running send_arp for $OCF_RESKEY_ip"
868 rm -f "$SENDARPPIDFILE"
869 fi
870 fi
871 local ip_status=`ip_served`
872 ocf_log info "IP status = $ip_status, IP_CIP=$IP_CIP"
873
874 if [ $ip_status = "no" ]; then
875 : Requested interface not in use
876 exit $OCF_SUCCESS
877 fi
878
879 if [ -n "$IP_CIP" ] && [ $ip_status != "partial2" ]; then
880 if [ $ip_status = "partial" ]; then
881 exit $OCF_SUCCESS
882 fi
883 echo "-$IP_INC_NO" >$IP_CIP_FILE
884 if [ "x$(cat $IP_CIP_FILE)" = "x" ]; then
885 ocf_log info $OCF_RESKEY_ip, $IP_CIP_HASH
886 i=1
887 while [ $i -le $IP_INC_GLOBAL ]; do
888 ocf_log info $i
889 $IPTABLES -D INPUT -d $OCF_RESKEY_ip -i $NIC -j CLUSTERIP \
890 --new \
891 --clustermac $IF_MAC \
892 --total-nodes $IP_INC_GLOBAL \
893 --local-node $i \
894 --hashmode $IP_CIP_HASH
895 i=`expr $i + 1`
896 done
897 else
898 ip_del_if="no"
899 fi
900 fi
901
902 if [ "$ip_del_if" = "yes" ]; then
903 delete_interface $OCF_RESKEY_ip $NIC $NETMASK
904 if [ $? -ne 0 ]; then
905 ocf_exit_reason "Unable to remove IP [${OCF_RESKEY_ip} from interface [ $NIC ]"
906 exit $OCF_ERR_GENERIC
907 fi
908
909 if ocf_is_true ${OCF_RESKEY_lvs_support}; then
910 restore_loopback "$OCF_RESKEY_ip"
911 fi
912 fi
913
914 exit $OCF_SUCCESS
915}
916
917ip_monitor() {
918 # TODO: Implement more elaborate monitoring like checking for
919 # interface health maybe via a daemon like FailSafe etc...
920
921 local ip_status=`ip_served`
922 case $ip_status in
923 ok)
924 return $OCF_SUCCESS
925 ;;
926 partial|no|partial2)
927 exit $OCF_NOT_RUNNING
928 ;;
929 *)
930 # Errors on this interface?
931 return $OCF_ERR_GENERIC
932 ;;
933 esac
934}
935
936# make sure that we have something to send ARPs with
937set_send_arp_program() {
938 ARP_SEND_FUN=run_send_arp
939 if [ -n "$OCF_RESKEY_arp_sender" ]; then
940 case "$OCF_RESKEY_arp_sender" in
941 send_arp)
942 check_binary $SENDARP
943 ;;
944 ipoibarping)
945 check_binary ipoibarping
946 ARP_SEND_FUN=run_send_ib_arp
947 ;;
948 *)
949 ocf_exit_reason "unrecognized arp_sender value: $OCF_RESKEY_arp_sender"
950 exit $OCF_ERR_CONFIGURED
951 ;;
952 esac
953 else
954 if is_infiniband; then
955 ARP_SEND_FUN=run_send_ib_arp
956 if ! have_binary ipoibarping; then
957 [ "$__OCF_ACTION" = start ] &&
958 ocf_log warn "using send_arp for infiniband because ipoibarping is not available (set arp_sender to \"send_arp\" to suppress this message)"
959 check_binary $SENDARP
960 ARP_SEND_FUN=run_send_arp
961 fi
962 fi
963 fi
964}
965
966ip_validate() {
967 check_binary $IP2UTIL
968 IP_CIP=
969
970 ip_init
971
972 set_send_arp_program
973
974 if [ -n "$IP_CIP" ]; then
975 check_binary $IPTABLES
976 check_binary $MODPROBE
977 fi
978
979# $BASEIP, $NETMASK, $NIC , $IP_INC_GLOBAL, and $BRDCAST have been checked within ip_init,
980# do not bother here.
981
982 if ocf_is_true "$OCF_RESKEY_unique_clone_address" &&
983 ! ocf_is_true "$OCF_RESKEY_CRM_meta_globally_unique"; then
984 ocf_exit_reason "unique_clone_address makes sense only with meta globally_unique set"
985 exit $OCF_ERR_CONFIGURED
986 fi
987
988 if ocf_is_decimal "$OCF_RESKEY_arp_interval" && [ $OCF_RESKEY_arp_interval -gt 0 ]; then
989 :
990 else
991 ocf_exit_reason "Invalid OCF_RESKEY_arp_interval [$OCF_RESKEY_arp_interval]"
992 exit $OCF_ERR_CONFIGURED
993 fi
994
995 if ocf_is_decimal "$OCF_RESKEY_arp_count" && [ $OCF_RESKEY_arp_count -gt 0 ]; then
996 :
997 else
998 ocf_exit_reason "Invalid OCF_RESKEY_arp_count [$OCF_RESKEY_arp_count]"
999 exit $OCF_ERR_CONFIGURED
1000 fi
1001
1002 if [ -n "$IP_CIP" ]; then
1003
1004 local valid=1
1005
1006 case $IP_CIP_HASH in
1007 sourceip|sourceip-sourceport|sourceip-sourceport-destport)
1008 ;;
1009 *)
1010 ocf_exit_reason "Invalid OCF_RESKEY_clusterip_hash [$IP_CIP_HASH]"
1011 exit $OCF_ERR_CONFIGURED
1012 ;;
1013 esac
1014
1015 if ocf_is_true ${OCF_RESKEY_lvs_support}; then
1016 ocf_exit_reason "LVS and load sharing not advised to try"
1017 exit $OCF_ERR_CONFIGURED
1018 fi
1019
1020 case $IF_MAC in
1021 [0-9a-zA-Z][13579bBdDfF][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z])
1022 ;;
1023 *)
1024 valid=0
1025 ;;
1026 esac
1027
1028 if [ $valid -eq 0 ]; then
1029 ocf_exit_reason "Invalid IF_MAC [$IF_MAC]"
1030 exit $OCF_ERR_CONFIGURED
1031 fi
1032
1033 fi
1034}
1035
1036if ocf_is_true "$OCF_RESKEY_unique_clone_address"; then
1037 prefix=`echo $OCF_RESKEY_ip | awk -F. '{print $1"."$2"."$3}'`
1038 suffix=`echo $OCF_RESKEY_ip | awk -F. '{print $4}'`
1039 suffix=`expr ${OCF_RESKEY_CRM_meta_clone:-0} + $suffix`
1040 OCF_RESKEY_ip="$prefix.$suffix"
1041fi
1042
1043case $__OCF_ACTION in
1044meta-data) meta_data
1045 ;;
1046usage|help) ip_usage
1047 exit $OCF_SUCCESS
1048 ;;
1049esac
1050
1051ip_validate
1052
1053case $__OCF_ACTION in
1054start) ip_start
1055 ;;
1056stop) ip_stop
1057 ;;
1058status) ip_status=`ip_served`
1059 if [ $ip_status = "ok" ]; then
1060 echo "running"
1061 exit $OCF_SUCCESS
1062 else
1063 echo "stopped"
1064 exit $OCF_NOT_RUNNING
1065 fi
1066 ;;
1067monitor) ip_monitor
1068 ;;
1069validate-all) ;;
1070*) ip_usage
1071 exit $OCF_ERR_UNIMPLEMENTED
1072 ;;
1073esac
1074# vi:sw=4:ts=8: