1#!/usr/local/bin/bash
2#
3#	$Id: IPaddr2.in,v 1.24 2006/08/09 13:01:54 lars Exp $
4#
5#       OCF Resource Agent compliant IPaddr2 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_preferred_lft
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_ip_default=""
73OCF_RESKEY_cidr_netmask_default=""
74OCF_RESKEY_broadcast_default=""
75OCF_RESKEY_iflabel_default=""
76OCF_RESKEY_cidr_netmask_default=""
77OCF_RESKEY_lvs_support_default=false
78OCF_RESKEY_lvs_ipv6_addrlabel_default=false
79OCF_RESKEY_lvs_ipv6_addrlabel_value_default=99
80OCF_RESKEY_clusterip_hash_default="sourceip-sourceport"
81OCF_RESKEY_mac_default=""
82OCF_RESKEY_unique_clone_address_default=false
83OCF_RESKEY_arp_interval_default=200
84OCF_RESKEY_arp_count_default=5
85OCF_RESKEY_arp_count_refresh_default=0
86OCF_RESKEY_arp_bg_default=true
87OCF_RESKEY_arp_sender_default=""
88OCF_RESKEY_send_arp_opts_default=""
89OCF_RESKEY_flush_routes_default="false"
90OCF_RESKEY_run_arping_default=false
91OCF_RESKEY_noprefixroute_default="false"
92OCF_RESKEY_preferred_lft_default="forever"
93OCF_RESKEY_network_namespace_default=""
94
95: ${OCF_RESKEY_ip=${OCF_RESKEY_ip_default}}
96: ${OCF_RESKEY_cidr_netmask=${OCF_RESKEY_cidr_netmask_default}}
97: ${OCF_RESKEY_broadcast=${OCF_RESKEY_broadcast_default}}
98: ${OCF_RESKEY_iflabel=${OCF_RESKEY_iflabel_default}}
99: ${OCF_RESKEY_lvs_support=${OCF_RESKEY_lvs_support_default}}
100: ${OCF_RESKEY_lvs_ipv6_addrlabel=${OCF_RESKEY_lvs_ipv6_addrlabel_default}}
101: ${OCF_RESKEY_lvs_ipv6_addrlabel_value=${OCF_RESKEY_lvs_ipv6_addrlabel_value_default}}
102: ${OCF_RESKEY_clusterip_hash=${OCF_RESKEY_clusterip_hash_default}}
103: ${OCF_RESKEY_mac=${OCF_RESKEY_mac_default}}
104: ${OCF_RESKEY_unique_clone_address=${OCF_RESKEY_unique_clone_address_default}}
105: ${OCF_RESKEY_arp_interval=${OCF_RESKEY_arp_interval_default}}
106: ${OCF_RESKEY_arp_count=${OCF_RESKEY_arp_count_default}}
107: ${OCF_RESKEY_arp_count_refresh=${OCF_RESKEY_arp_count_refresh_default}}
108: ${OCF_RESKEY_arp_bg=${OCF_RESKEY_arp_bg_default}}
109: ${OCF_RESKEY_arp_sender=${OCF_RESKEY_arp_sender_default}}
110: ${OCF_RESKEY_send_arp_opts=${OCF_RESKEY_send_arp_opts_default}}
111: ${OCF_RESKEY_flush_routes=${OCF_RESKEY_flush_routes_default}}
112: ${OCF_RESKEY_run_arping=${OCF_RESKEY_run_arping_default}}
113: ${OCF_RESKEY_noprefixroute=${OCF_RESKEY_noprefixroute_default}}
114: ${OCF_RESKEY_preferred_lft=${OCF_RESKEY_preferred_lft_default}}
115: ${OCF_RESKEY_network_namespace=${OCF_RESKEY_network_namespace_default}}
116
117#######################################################################
118
119SENDARP=$HA_BIN/send_arp
120SENDUA=$HA_BIN/send_ua
121FINDIF=findif
122VLDIR=$HA_RSCTMP
123SENDARPPIDDIR=$HA_RSCTMP
124CIP_lockfile=$HA_RSCTMP/IPaddr2-CIP-${OCF_RESKEY_ip}
125
126IPADDR2_CIP_IPTABLES=$IPTABLES
127
128#######################################################################
129
130meta_data() {
131	cat <<END
132<?xml version="1.0"?>
133<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
134<resource-agent name="IPaddr2">
135<version>1.0</version>
136
137<longdesc lang="en">
138This Linux-specific resource manages IP alias IP addresses.
139It can add an IP alias, or remove one.
140In addition, it can implement Cluster Alias IP functionality
141if invoked as a clone resource.
142
143If used as a clone, "shared address with a trivial, stateless
144(autonomous) load-balancing/mutual exclusion on ingress" mode gets
145applied (as opposed to "assume resource uniqueness" mode otherwise).
146For that, Linux firewall (kernel and userspace) is assumed, and since
147recent distributions are ambivalent in plain "iptables" command to
148particular back-end resolution, "iptables-legacy" (when present) gets
149prioritized so as to avoid incompatibilities (note that respective
150ipt_CLUSTERIP firewall extension in use here is, at the same time,
151marked deprecated, yet said "legacy" layer can make it workable,
152literally, to this day) with "netfilter" one (as in "iptables-nft").
153In that case, you should explicitly set clone-node-max &gt;= 2,
154and/or clone-max &lt; number of nodes. In case of node failure,
155clone instances need to be re-allocated on surviving nodes.
156This would not be possible if there is already an instance
157on those nodes, and clone-node-max=1 (which is the default).
158</longdesc>
159
160<shortdesc lang="en">Manages virtual IPv4 and IPv6 addresses (Linux specific version)</shortdesc>
161
162<parameters>
163<parameter name="ip" unique="1" required="1">
164<longdesc lang="en">
165The IPv4 (dotted quad notation) or IPv6 address (colon hexadecimal notation)
166example IPv4 "192.168.1.1".
167example IPv6 "2001:db8:DC28:0:0:FC57:D4C8:1FFF".
168</longdesc>
169<shortdesc lang="en">IPv4 or IPv6 address</shortdesc>
170<content type="string" default="${OCF_RESKEY_ip_default}" />
171</parameter>
172<parameter name="nic" unique="0">
173<longdesc lang="en">
174The base network interface on which the IP address will be brought
175online. 
176If left empty, the script will try and determine this from the
177routing table.
178
179Do NOT specify an alias interface in the form eth0:1 or anything here;
180rather, specify the base interface only.
181If you want a label, see the iflabel parameter.
182
183Prerequisite:
184
185There must be at least one static IP address, which is not managed by
186the cluster, assigned to the network interface.
187If you can not assign any static IP address on the interface,
188modify this kernel parameter:
189
190sysctl -w net.ipv4.conf.all.promote_secondaries=1 # (or per device)
191</longdesc>
192<shortdesc lang="en">Network interface</shortdesc>
193<content type="string"/>
194</parameter>
195
196<parameter name="cidr_netmask">
197<longdesc lang="en">
198The netmask for the interface in CIDR format
199(e.g., 24 and not 255.255.255.0)
200
201If unspecified, the script will also try to determine this from the
202routing table.
203</longdesc>
204<shortdesc lang="en">CIDR netmask</shortdesc>
205<content type="string" default="${OCF_RESKEY_cidr_netmask_default}"/>
206</parameter>
207
208<parameter name="broadcast">
209<longdesc lang="en">
210Broadcast address associated with the IP. It is possible to use the
211special symbols '+' and '-' instead of the broadcast address. In this
212case, the broadcast address is derived by setting/resetting the host
213bits of the interface prefix.
214</longdesc>
215<shortdesc lang="en">Broadcast address</shortdesc>
216<content type="string" default="${OCF_RESKEY_broadcast_default}"/>
217</parameter>
218
219<parameter name="iflabel">
220<longdesc lang="en">
221You can specify an additional label for your IP address here.
222This label is appended to your interface name.
223
224The kernel allows alphanumeric labels up to a maximum length of 15
225characters including the interface name and colon (e.g. eth0:foobar1234)
226
227A label can be specified in nic parameter but it is deprecated.
228If a label is specified in nic name, this parameter has no effect.
229</longdesc>
230<shortdesc lang="en">Interface label</shortdesc>
231<content type="string" default="${OCF_RESKEY_iflabel_default}"/>
232</parameter>
233
234<parameter name="lvs_support">
235<longdesc lang="en">
236Enable support for LVS Direct Routing configurations. In case a IP
237address is stopped, only move it to the loopback device to allow the
238local node to continue to service requests, but no longer advertise it
239on the network.
240
241Notes for IPv6:
242It is not necessary to enable this option on IPv6.
243Instead, enable 'lvs_ipv6_addrlabel' option for LVS-DR usage on IPv6.
244</longdesc>
245<shortdesc lang="en">Enable support for LVS DR</shortdesc>
246<content type="boolean" default="${OCF_RESKEY_lvs_support_default}"/>
247</parameter>
248
249<parameter name="lvs_ipv6_addrlabel">
250<longdesc lang="en">
251Enable adding IPv6 address label so IPv6 traffic originating from
252the address's interface does not use this address as the source.
253This is necessary for LVS-DR health checks to realservers to work. Without it,
254the most recently added IPv6 address (probably the address added by IPaddr2)
255will be used as the source address for IPv6 traffic from that interface and
256since that address exists on loopback on the realservers, the realserver
257response to pings/connections will never leave its loopback.
258See RFC3484 for the detail of the source address selection.
259
260See also 'lvs_ipv6_addrlabel_value' parameter.
261</longdesc>
262<shortdesc lang="en">Enable adding IPv6 address label.</shortdesc>
263<content type="boolean" default="${OCF_RESKEY_lvs_ipv6_addrlabel_default}"/>
264</parameter>
265
266<parameter name="lvs_ipv6_addrlabel_value">
267<longdesc lang="en">
268Specify IPv6 address label value used when 'lvs_ipv6_addrlabel' is enabled.
269The value should be an unused label in the policy table
270which is shown by 'ip addrlabel list' command.
271You would rarely need to change this parameter.
272</longdesc>
273<shortdesc lang="en">IPv6 address label value.</shortdesc>
274<content type="integer" default="${OCF_RESKEY_lvs_ipv6_addrlabel_value_default}"/>
275</parameter>
276
277<parameter name="mac">
278<longdesc lang="en">
279Set the interface MAC address explicitly. Currently only used in case of
280the Cluster IP Alias. Leave empty to chose automatically.
281
282</longdesc>
283<shortdesc lang="en">Cluster IP MAC address</shortdesc>
284<content type="string" default="${OCF_RESKEY_mac_default}"/>
285</parameter>
286
287<parameter name="clusterip_hash">
288<longdesc lang="en">
289Specify the hashing algorithm used for the Cluster IP functionality.
290
291</longdesc>
292<shortdesc lang="en">Cluster IP hashing function</shortdesc>
293<content type="string" default="${OCF_RESKEY_clusterip_hash_default}"/>
294</parameter>
295
296<parameter name="unique_clone_address">
297<longdesc lang="en">
298If true, add the clone ID to the supplied value of IP to create
299a unique address to manage 
300</longdesc>
301<shortdesc lang="en">Create a unique address for cloned instances</shortdesc>
302<content type="boolean" default="${OCF_RESKEY_unique_clone_address_default}"/>
303</parameter>
304
305<parameter name="arp_interval">
306<longdesc lang="en">
307Specify the interval between unsolicited ARP packets in milliseconds.
308
309This parameter is deprecated and used for the backward compatibility only.
310It is effective only for the send_arp binary which is built with libnet,
311and send_ua for IPv6. It has no effect for other arp_sender.
312</longdesc>
313<shortdesc lang="en">ARP packet interval in ms (deprecated)</shortdesc>
314<content type="integer" default="${OCF_RESKEY_arp_interval_default}"/>
315</parameter>
316
317<parameter name="arp_count">
318<longdesc lang="en">
319Number of unsolicited ARP packets to send at resource initialization.
320</longdesc>
321<shortdesc lang="en">ARP packet count sent during initialization</shortdesc>
322<content type="integer" default="${OCF_RESKEY_arp_count_default}"/>
323</parameter>
324
325<parameter name="arp_count_refresh">
326<longdesc lang="en">
327Number of unsolicited ARP packets to send during resource monitoring. Doing
328so helps mitigate issues of stuck ARP caches resulting from split-brain
329situations.
330</longdesc>
331<shortdesc lang="en">ARP packet count sent during monitoring</shortdesc>
332<content type="integer" default="${OCF_RESKEY_arp_count_refresh_default}"/>
333</parameter>
334
335<parameter name="arp_bg">
336<longdesc lang="en">
337Whether or not to send the ARP packets in the background.
338</longdesc>
339<shortdesc lang="en">ARP from background</shortdesc>
340<content type="string" default="${OCF_RESKEY_arp_bg_default}"/>
341</parameter>
342
343<parameter name="arp_sender">
344<longdesc lang="en">
345The program to send ARP packets with on start. Available options are:
346 - send_arp: default
347 - ipoibarping: default for infiniband interfaces if ipoibarping is available
348 - iputils_arping: use arping in iputils package
349 - libnet_arping: use another variant of arping based on libnet
350</longdesc>
351<shortdesc lang="en">ARP sender</shortdesc>
352<content type="string" default="${OCF_RESKEY_arp_sender_default}"/>
353</parameter>
354
355<parameter name="send_arp_opts">
356<longdesc lang="en">
357Extra options to pass to the arp_sender program.
358Available options are vary depending on which arp_sender is used.
359
360A typical use case is specifying '-A' for iputils_arping to use
361ARP REPLY instead of ARP REQUEST as Gratuitous ARPs.
362</longdesc>
363<shortdesc lang="en">Options for ARP sender</shortdesc>
364<content type="string" default="${OCF_RESKEY_send_arp_opts_default}"/>
365</parameter>
366
367<parameter name="flush_routes">
368<longdesc lang="en">
369Flush the routing table on stop. This is for
370applications which use the cluster IP address
371and which run on the same physical host that the
372IP address lives on. The Linux kernel may force that
373application to take a shortcut to the local loopback
374interface, instead of the interface the address
375is really bound to. Under those circumstances, an
376application may, somewhat unexpectedly, continue
377to use connections for some time even after the
378IP address is deconfigured. Set this parameter in
379order to immediately disable said shortcut when the
380IP address goes away.
381</longdesc>
382<shortdesc lang="en">Flush kernel routing table on stop</shortdesc>
383<content type="boolean" default="${OCF_RESKEY_flush_routes_default}"/>
384</parameter>
385
386<parameter name="run_arping">
387<longdesc lang="en">
388Whether or not to run arping for IPv4 collision detection check.
389</longdesc>
390<shortdesc lang="en">Run arping for IPv4 collision detection check</shortdesc>
391<content type="string" default="${OCF_RESKEY_run_arping_default}"/>
392</parameter>
393
394<parameter name="noprefixroute">
395<longdesc lang="en">
396Use noprefixroute flag (see 'man ip-address').
397</longdesc>
398<shortdesc lang="en">Use noprefixroute flag</shortdesc>
399<content type="string" default="${OCF_RESKEY_noprefixroute_default}"/>
400</parameter>
401
402<parameter name="preferred_lft">
403<longdesc lang="en">
404For IPv6, set the preferred lifetime of the IP address.
405This can be used to ensure that the created IP address will not
406be used as a source address for routing.
407Expects a value as specified in section 5.5.4 of RFC 4862.
408</longdesc>
409<shortdesc lang="en">IPv6 preferred lifetime</shortdesc>
410<content type="string" default="${OCF_RESKEY_preferred_lft_default}"/>
411</parameter>
412
413<parameter name="network_namespace">
414<longdesc lang="en">
415Specifies the network namespace to operate within.
416The namespace must already exist, and the interface to be used must be within
417the namespace.
418</longdesc>
419<shortdesc lang="en">Network namespace to use</shortdesc>
420<content type="string" default="${OCF_RESKEY_network_namespace_default}"/>
421</parameter>
422</parameters>
423
424<actions>
425<action name="start"   timeout="20s" />
426<action name="stop"    timeout="20s" />
427<action name="status" depth="0"  timeout="20s" interval="10s" />
428<action name="monitor" depth="0"  timeout="20s" interval="10s" />
429<action name="meta-data"  timeout="5s" />
430<action name="validate-all"  timeout="20s" />
431</actions>
432</resource-agent>
433END
434
435	exit $OCF_SUCCESS
436}
437
438ip_init() {
439	local rc
440
441	if [ X`uname -s` != "XLinux" ]; then
442		ocf_exit_reason "IPaddr2 only supported Linux."
443		exit $OCF_ERR_INSTALLED
444	fi
445
446	if [ X"$OCF_RESKEY_ip" = "X" ] && [ "$__OCF_ACTION" != "stop" ]; then
447		ocf_exit_reason "IP address (the ip parameter) is mandatory"
448		exit $OCF_ERR_CONFIGURED
449	fi
450
451	if
452          case $__OCF_ACTION in
453            start|stop)		ocf_is_root;;
454            *)			true;;
455          esac
456        then
457          : YAY!
458        else
459		ocf_exit_reason "You must be root for $__OCF_ACTION operation."
460		exit $OCF_ERR_PERM
461	fi
462
463	BASEIP="$OCF_RESKEY_ip"
464	BRDCAST="$OCF_RESKEY_broadcast"
465	NIC="$OCF_RESKEY_nic"
466        # Note: We had a version out there for a while which used
467        # netmask instead of cidr_netmask. Don't remove this aliasing code!
468        if
469          [ ! -z "$OCF_RESKEY_netmask" -a -z "$OCF_RESKEY_cidr_netmask" ]
470        then
471	  OCF_RESKEY_cidr_netmask=$OCF_RESKEY_netmask
472	  export OCF_RESKEY_cidr_netmask
473        fi
474	NETMASK="$OCF_RESKEY_cidr_netmask"
475	IFLABEL="$OCF_RESKEY_iflabel"
476	IF_MAC="$OCF_RESKEY_mac"
477
478	IP_INC_GLOBAL=${OCF_RESKEY_CRM_meta_clone_max:-1}
479	IP_INC_NO=`expr ${OCF_RESKEY_CRM_meta_clone:-0} + 1`
480
481	if ocf_is_true ${OCF_RESKEY_lvs_support} && [ $IP_INC_GLOBAL -gt 1 ]; then
482		ocf_exit_reason "LVS and load sharing do not go together well"
483		exit $OCF_ERR_CONFIGURED
484	fi
485
486	if ocf_is_decimal "$IP_INC_GLOBAL" && [ $IP_INC_GLOBAL -gt 0 ]; then
487		:
488	else
489		ocf_exit_reason "Invalid meta-attribute clone_max [$IP_INC_GLOBAL], should be positive integer"
490		exit $OCF_ERR_CONFIGURED
491	fi
492
493	echo $OCF_RESKEY_ip | grep -qs ":"
494	if [ $? -ne 0 ];then
495		FAMILY=inet
496		if ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
497			ocf_exit_reason "IPv4 does not support lvs_ipv6_addrlabel"
498			exit $OCF_ERR_CONFIGURED
499		fi
500	else
501		FAMILY=inet6
502		# address sanitization defined in RFC5952
503		SANITIZED_IP=$($IP2UTIL route get $OCF_RESKEY_ip 2> /dev/null | awk '$1~/:/ {print $1}  $2~/:/ {print $2}')
504                if [ -n "$SANITIZED_IP" ]; then
505                    OCF_RESKEY_ip="$SANITIZED_IP"
506                fi
507
508		if ocf_is_true $OCF_RESKEY_lvs_support ;then
509			ocf_exit_reason "The IPv6 does not support lvs_support"
510			exit $OCF_ERR_CONFIGURED
511		fi
512		if ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
513			if ocf_is_decimal "$OCF_RESKEY_lvs_ipv6_addrlabel_value" && [ $OCF_RESKEY_lvs_ipv6_addrlabel_value -ge 0 ]; then
514			    :
515			else
516			    ocf_exit_reason "Invalid lvs_ipv6_addrlabel_value [$OCF_RESKEY_lvs_ipv6_addrlabel_value], should be positive integer"
517			    exit $OCF_ERR_CONFIGURED
518			fi
519		fi
520	fi
521
522	# support nic:iflabel format in nic parameter
523	case $NIC in
524	    *:*)
525		IFLABEL=`echo $NIC | sed 's/[^:]*://'`
526		NIC=`echo $NIC | sed 's/:.*//'`
527		# only the base name should be passed to findif
528		OCF_RESKEY_nic=$NIC
529		;;
530	esac
531
532	# $FINDIF takes its parameters from the environment
533	#
534	NICINFO=`$FINDIF`
535	rc=$?
536	if
537	  [ $rc -eq 0 ]
538        then
539	    NICINFO=`echo "$NICINFO" | sed -e 's/netmask\ //;s/broadcast\ //'`
540	    NIC=`echo "$NICINFO" | cut -d" " -f1`
541	    NETMASK=`echo "$NICINFO" | cut -d" " -f2`
542	    BRDCAST=`echo "$NICINFO" | cut -d" " -f3`
543	else
544		# findif couldn't find the interface
545		if ocf_is_probe; then
546			ocf_log info "[$FINDIF] failed"
547			exit $OCF_NOT_RUNNING
548		elif [ "$__OCF_ACTION" = stop ]; then
549			ocf_log warn "[$FINDIF] failed"
550			exit $OCF_SUCCESS
551		else
552			ocf_exit_reason "[$FINDIF] failed"
553			exit $rc
554		fi
555	fi
556
557	SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$OCF_RESKEY_ip"
558
559	if [ -n "$IFLABEL" ]; then
560		IFLABEL=${NIC}:${IFLABEL}
561		if [ ${#IFLABEL} -gt 15 ]; then
562			ocf_exit_reason "Interface label [$IFLABEL] exceeds maximum character limit of 15"
563			exit $OCF_ERR_CONFIGURED
564		fi
565	fi
566
567	if [ "$IP_INC_GLOBAL" -gt 1 ] && ! ocf_is_true "$OCF_RESKEY_unique_clone_address"; then
568		IP_CIP="yes"
569		IP_CIP_HASH="${OCF_RESKEY_clusterip_hash}"
570		if [ -z "$IF_MAC" ]; then
571			# Choose a MAC
572			# 1. Concatenate some input together
573			# 2. This doesn't need to be a cryptographically
574			#    secure hash.
575			# 3. Drop everything after the first 6 octets (12 chars)
576			# 4. Delimit the octets with ':'
577			# 5. Make sure the first octet is odd,
578			#    so the result is a multicast MAC
579			IF_MAC=`echo $OCF_RESKEY_ip $NETMASK $BRDCAST |	\
580				md5 |				\
581				sed -e 's#\(............\).*#\1#'	\
582				    -e 's#..#&:#g; s#:$##'		\
583				    -e 's#^\(.\)[02468aAcCeE]#\11#'`
584		fi
585		IP_CIP_FILE="/proc/net/ipt_CLUSTERIP/$OCF_RESKEY_ip"
586	fi
587}
588
589#
590#	Find out which interfaces serve the given IP address and netmask.
591#	The arguments are an IP address and a netmask.
592#	Its output are interface names devided by spaces (e.g., "eth0 eth1").
593#
594find_interface() {
595	local ipaddr="$1"
596	local netmask="$2"
597
598	#
599	# List interfaces but exclude FreeS/WAN ipsecN virtual interfaces
600	#
601	local iface="`$IP2UTIL -o -f $FAMILY addr show \
602		| grep "\ $ipaddr/$netmask" \
603		| cut -d ' ' -f2 \
604		| grep -v '^ipsec[0-9][0-9]*$'`"
605
606	echo "$iface"
607	return 0
608}
609
610#
611#        Delete an interface
612#
613delete_interface () {
614	ipaddr="$1"
615	iface="$2"
616	netmask="$3"
617
618	CMD="$IP2UTIL -f $FAMILY addr delete $ipaddr/$netmask dev $iface"
619
620	ocf_run $CMD || return $OCF_ERR_GENERIC
621
622	if ocf_is_true $OCF_RESKEY_flush_routes; then
623	    ocf_run $IP2UTIL route flush cache
624	fi
625
626	if [ "$FAMILY" = "inet6" ] && ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
627	    delete_ipv6_addrlabel $ipaddr
628	fi
629
630	return $OCF_SUCCESS
631}
632
633#
634#        Add an interface
635#
636add_interface () {
637	local cmd msg ipaddr netmask broadcast iface label
638
639	ipaddr="$1"
640	netmask="$2"
641	broadcast="$3"
642	iface="$4"
643	label="$5"
644
645	if [ "$FAMILY" = "inet" ] && ocf_is_true $OCF_RESKEY_run_arping &&
646	   check_binary arping; then
647		arping -q -c 2 -w 3 -D -I $iface $ipaddr
648		if [ $? = 1 ]; then
649			ocf_log err "IPv4 address collision $ipaddr [DAD]"
650			return $OCF_ERR_GENERIC
651		fi
652	fi
653
654	if [ "$FAMILY" = "inet6" ] && ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
655	    add_ipv6_addrlabel $ipaddr
656	fi
657
658	cmd="$IP2UTIL -f $FAMILY addr add $ipaddr/$netmask dev $iface"
659	msg="Adding $FAMILY address $ipaddr/$netmask to device $iface"
660	if [ "$broadcast" != "none" ]; then
661		cmd="$IP2UTIL -f $FAMILY addr add $ipaddr/$netmask brd $broadcast dev $iface"
662		msg="Adding $FAMILY address $ipaddr/$netmask with broadcast address $broadcast to device $iface"
663	fi
664
665	if ocf_is_true "${OCF_RESKEY_noprefixroute}"; then
666		cmd="$cmd noprefixroute"
667		msg="${msg} (with noprefixroute)"
668	fi
669
670	if [ ! -z "$label" ]; then
671		cmd="$cmd label $label"
672		msg="${msg} (with label $label)"
673	fi
674	if [ "$FAMILY" = "inet6" ] ;then
675		cmd="$cmd preferred_lft $OCF_RESKEY_preferred_lft"
676		msg="${msg} (with preferred_lft $OCF_RESKEY_preferred_lft)"
677	fi
678
679	ocf_log info "$msg"
680	ocf_run $cmd || return $OCF_ERR_GENERIC
681
682	msg="Bringing device $iface up"
683	cmd="$IP2UTIL link set $iface up"
684	ocf_log info "$msg"
685	ocf_run $cmd || return $OCF_ERR_GENERIC
686
687	return $OCF_SUCCESS
688}
689
690#
691#        Delete a route
692#
693delete_route () {
694	prefix="$1"
695	iface="$2"
696
697	CMD="$IP2UTIL route delete $prefix dev $iface"
698
699	ocf_log info "$CMD"
700	$CMD
701
702	return $?
703}
704
705#      On Linux systems the (hidden) loopback interface may
706#      conflict with the requested IP address. If so, this
707#      unoriginal code will remove the offending loopback address
708#      and save it in VLDIR so it can be added back in later
709#      when the IPaddr is released.
710#
711#      TODO: This is very ugly and should be controlled by an additional
712#      instance parameter. Or even: multi-state, with the IP only being
713#      "active" on the master!?
714#
715remove_conflicting_loopback() {
716	ipaddr="$1"
717	netmask="$2"
718	broadcast="$3"
719	ifname="$4"
720
721	ocf_log info "Removing conflicting loopback $ifname."
722	if
723		echo "$ipaddr $netmask $broadcast $ifname" > "$VLDIR/$ipaddr"
724	then
725		: Saved loopback information in $VLDIR/$ipaddr
726	else
727		ocf_log err "Could not save conflicting loopback $ifname." \
728		       "it will not be restored."
729	fi
730	delete_interface "$ipaddr" "$ifname" "$netmask"
731	# Forcibly remove the route (if it exists) to the loopback.
732	delete_route "$ipaddr" "$ifname"
733}
734
735#
736#	On Linux systems the (hidden) loopback interface may
737#	need to be restored if it has been taken down previously
738#	by remove_conflicting_loopback()
739#
740restore_loopback() {
741	ipaddr="$1"
742
743	if [ -s "$VLDIR/$ipaddr" ]; then
744		ifinfo=`cat "$VLDIR/$ipaddr"`
745		ocf_log info "Restoring loopback IP Address " \
746		    "$ifinfo."
747		add_interface $ifinfo
748		rm -f "$VLDIR/$ipaddr"
749	fi
750}
751
752add_ipv6_addrlabel() {
753	local cmd ipaddr value
754	ipaddr="$1"
755	value="$OCF_RESKEY_lvs_ipv6_addrlabel_value"
756
757	cmd="$IP2UTIL addrlabel add prefix $ipaddr label $value"
758	ocf_log info "Adding IPv6 address label prefix $ipaddr label $value"
759	ocf_run $cmd || ocf_log warn "$cmd failed."
760}
761
762delete_ipv6_addrlabel() {
763	local cmd ipaddr value
764	ipaddr="$1"
765	value="$OCF_RESKEY_lvs_ipv6_addrlabel_value"
766
767	cmd="$IP2UTIL addrlabel del prefix $ipaddr label $value"
768	ocf_run $cmd # an error can be ignored
769}
770
771is_infiniband() {
772	$IP2UTIL link show $NIC | grep link/infiniband >/dev/null
773}
774
775log_arp_sender() {
776    local cmdline
777    local output
778    local rc
779    cmdline="$@"
780
781    output=$($cmdline 2>&1)
782    rc=$?
783    if [ $rc -ne 0 ] && \
784       [ "$ARP_SENDER" != "libnet_arping" ] ; then
785        # libnet_arping always return an error as no answers
786        ocf_log err "Could not send gratuitous arps: rc=$rc"
787    fi
788    ocf_log $LOGLEVEL "$output"
789}
790
791# wrapper function to manage PID file to run arping in background
792run_with_pidfile() {
793    local cmdline
794    local pid
795    local rc
796
797    cmdline="$@"
798
799    $cmdline &
800    pid=$!
801    echo "$pid" > $SENDARPPIDFILE
802    wait $pid
803    rc=$?
804    rm -f $SENDARPPIDFILE
805    return $rc
806}
807
808build_arp_sender_cmd() {
809    case "$ARP_SENDER" in
810	send_arp)
811	    if [ "x$IP_CIP" = "xyes" ] ; then
812	        if [ x = "x$IF_MAC" ] ; then
813		    MY_MAC=auto
814	        else
815		    # send_arp.linux should return without doing anything in this case
816		    MY_MAC=`echo ${IF_MAC} | sed -e 's/://g'`
817	        fi
818	    else
819		    MY_MAC=auto
820	    fi
821
822	    ARGS="$OCF_RESKEY_send_arp_opts -i $OCF_RESKEY_arp_interval -r $ARP_COUNT -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip $MY_MAC not_used not_used"
823	    ARP_SENDER_CMD="$SENDARP $ARGS"
824	    ;;
825	iputils_arping)
826	    ARGS="$OCF_RESKEY_send_arp_opts -U -c $ARP_COUNT -I $NIC $OCF_RESKEY_ip"
827	    ARP_SENDER_CMD="run_with_pidfile arping $ARGS"
828	    ;;
829	libnet_arping)
830	    ARGS="$OCF_RESKEY_send_arp_opts -U -c $ARP_COUNT -i $NIC -S $OCF_RESKEY_ip $OCF_RESKEY_ip"
831	    ARP_SENDER_CMD="run_with_pidfile arping $ARGS"
832	    ;;
833	ipoibarping)
834	    ARGS="-q -c $ARP_COUNT -U -I $NIC $OCF_RESKEY_ip"
835	    ARP_SENDER_CMD="ipoibarping $ARGS"
836	    ;;
837	*)
838	    # should not occur
839	    ocf_exit_reason "unrecognized arp_sender value: $ARP_SENDER"
840	    exit $OCF_ERR_GENERIC
841	    ;;
842    esac
843}
844
845#
846# Send Unsolicited ARPs to update neighbor's ARP cache
847#
848run_arp_sender() {
849	if [ "x$1" = "xrefresh" ] ; then
850		ARP_COUNT=$OCF_RESKEY_arp_count_refresh
851		LOGLEVEL=debug
852	else
853		ARP_COUNT=$OCF_RESKEY_arp_count
854		LOGLEVEL=info
855	fi
856	if [ $ARP_COUNT -eq 0 ] ; then
857		return
858	fi
859
860	# do not need to send Gratuitous ARPs in the Cluster IP configuration
861	# except send_arp.libnet binary to retain the old behavior
862	if [ "x$IP_CIP" = "xyes" ] && \
863	   [ "x$ARP_SENDER" != "xsend_arp" ] ; then
864		ocf_log info "Gratuitous ARPs are not sent in the Cluster IP configuration"
865		return
866	fi
867
868        # prepare arguments for each arp sender program
869        # $ARP_SENDER_CMD should be set
870	build_arp_sender_cmd
871
872	ocf_log $LOGLEVEL "$ARP_SENDER_CMD"
873
874	if ocf_is_true $OCF_RESKEY_arp_bg; then
875		log_arp_sender $ARP_SENDER_CMD &
876	else
877		log_arp_sender $ARP_SENDER_CMD
878	fi
879}
880
881
882#
883# Run send_ua to note send ICMPv6 Unsolicited Neighbor Advertisements.
884#
885run_send_ua() {
886	local i
887
888	# Duplicate Address Detection [DAD]
889	# Kernel will flag the IP as 'tentative' until it ensured that
890	# there is no duplicates.
891	# If there is, it will flag it as 'dadfailed'
892	for i in $(seq 1 10); do
893		ipstatus=$($IP2UTIL -o -f $FAMILY addr show dev $NIC to $OCF_RESKEY_ip/$NETMASK)
894		case "$ipstatus" in
895		*dadfailed*)
896			ocf_log err "IPv6 address collision $OCF_RESKEY_ip [DAD]"
897			$IP2UTIL -f $FAMILY addr del dev $NIC $OCF_RESKEY_ip/$NETMASK
898			if [ $? -ne 0 ]; then
899				ocf_log err "Could not delete IPv6 address"
900			fi
901			return $OCF_ERR_GENERIC
902			;;
903		*tentative*)
904			if [ $i -eq 10 ]; then
905				ocf_log warn "IPv6 address : DAD is still in tentative"
906			fi
907			;;
908		*)
909			break
910			;;
911		esac
912		sleep 1
913	done
914	# Now the address should be usable
915
916	ARGS="-i $OCF_RESKEY_arp_interval -c $OCF_RESKEY_arp_count $OCF_RESKEY_ip $NETMASK $NIC"
917	ocf_log info "$SENDUA $ARGS"
918	$SENDUA $ARGS || ocf_log err "Could not send ICMPv6 Unsolicited Neighbor Advertisements."
919}
920
921# Do we already serve this IP address on the given $NIC?
922#
923# returns:
924# ok = served (for CIP: + hash bucket)
925# partial = served and no hash bucket (CIP only)
926# partial2 = served and no CIP iptables rule
927# no = nothing
928#
929ip_served() {
930	if [ -z "$NIC" ]; then # no nic found or specified
931		echo "no"
932		return 0
933	fi
934
935	cur_nic="`find_interface $OCF_RESKEY_ip $NETMASK`"
936
937	if [ -z "$cur_nic" ]; then
938		echo "no"
939		return 0
940	fi
941
942	if [ -z "$IP_CIP" ]; then
943		for i in $cur_nic; do
944			# only mark as served when on the same interfaces as $NIC
945			[ "$i" = "$NIC" ] || continue
946			echo "ok"
947			return 0
948		done
949		# There used to be logic here to pretend "not served",
950		# if ${OCF_RESKEY_lvs_support} was enabled, and the IP was
951		# found active on "lo*" only.  With lvs_support on, you should
952		# have NIC != lo, so thats already filtered
953		# by the continue above.
954
955		echo "no"
956		return 0
957	fi
958
959	# Special handling for the CIP:
960	if [ ! -e $IP_CIP_FILE ]; then
961		echo "partial2"
962		return 0
963	fi
964	if egrep -q "(^|,)${IP_INC_NO}(,|$)" $IP_CIP_FILE ; then
965		echo "ok"
966		return 0
967	else
968		echo "partial"
969		return 0
970	fi
971
972	exit $OCF_ERR_GENERIC
973}
974
975#######################################################################
976
977ip_usage() {
978	cat <<END
979usage: $0 {start|stop|status|monitor|validate-all|meta-data}
980
981Expects to have a fully populated OCF RA-compliant environment set.
982END
983}
984
985ip_start() {
986	if [ -z "$NIC" ]; then
987		ocf_exit_reason "No nic found or specified"
988		exit $OCF_ERR_CONFIGURED
989	fi
990
991	if [ -n "$IP_CIP" ]; then
992	    # Cluster IPs need special processing when the first bucket
993	    #  is added to the node... take a lock to make sure only one
994	    #  process executes that code
995	    ocf_take_lock $CIP_lockfile
996	    ocf_release_lock_on_exit $CIP_lockfile
997	fi
998
999	#
1000	#	Do we already service this IP address on $NIC?
1001	#
1002	local ip_status=`ip_served`
1003
1004	if [ "$ip_status" = "ok" ]; then
1005		exit $OCF_SUCCESS
1006	fi
1007
1008	if [ -n "$IP_CIP" ] && ([ $ip_status = "no" ] || [ $ip_status = "partial2" ]); then
1009		$MODPROBE ip_conntrack
1010		$IPADDR2_CIP_IPTABLES -I INPUT -d $OCF_RESKEY_ip -i $NIC -j CLUSTERIP \
1011				--new \
1012				--clustermac $IF_MAC \
1013				--total-nodes $IP_INC_GLOBAL \
1014				--local-node $IP_INC_NO \
1015				--hashmode $IP_CIP_HASH
1016		if [ $? -ne 0 ]; then
1017			ocf_exit_reason "iptables failed"
1018			exit $OCF_ERR_GENERIC
1019		fi
1020	fi
1021
1022	if [ -n "$IP_CIP" ] && [ $ip_status = "partial" ]; then
1023		echo "+$IP_INC_NO" >$IP_CIP_FILE
1024	fi
1025
1026	if [ "$ip_status" = "no" ]; then
1027		if ocf_is_true ${OCF_RESKEY_lvs_support}; then
1028			for i in `find_interface $OCF_RESKEY_ip 32`; do
1029				case $i in
1030				lo*)
1031					remove_conflicting_loopback $OCF_RESKEY_ip 32 255.255.255.255 lo
1032					;;
1033				esac
1034			done
1035		fi
1036
1037		add_interface $OCF_RESKEY_ip $NETMASK ${BRDCAST:-none} $NIC $IFLABEL
1038		rc=$?
1039
1040		if [ $rc -ne $OCF_SUCCESS ]; then
1041			ocf_exit_reason "Failed to add $OCF_RESKEY_ip"
1042			exit $rc
1043		fi
1044	fi
1045
1046	case $NIC in
1047	lo*)
1048		: no need to run send_arp on loopback
1049		;;
1050	*)
1051		if [ $FAMILY = "inet" ];then
1052		    run_arp_sender
1053		else
1054		    if [ -x $SENDUA ]; then
1055			run_send_ua
1056			if [ $? -ne 0 ]; then
1057				ocf_exit_reason "run_send_ua failed."
1058				exit $OCF_ERR_GENERIC
1059			fi
1060		    fi
1061		fi
1062		;;
1063	esac
1064	exit $OCF_SUCCESS
1065}
1066
1067ip_stop() {
1068	local ip_del_if="yes"
1069	if [ -n "$IP_CIP" ]; then
1070	    # Cluster IPs need special processing when the last bucket
1071	    #  is removed from the node... take a lock to make sure only one
1072	    #  process executes that code
1073	    ocf_take_lock $CIP_lockfile
1074	    ocf_release_lock_on_exit $CIP_lockfile
1075	fi
1076
1077	if [ -f "$SENDARPPIDFILE" ] ; then
1078		kill `cat "$SENDARPPIDFILE"`
1079		if [ $? -ne 0 ]; then
1080			ocf_log warn "Could not kill previously running send_arp for $OCF_RESKEY_ip"
1081		else
1082			ocf_log info "killed previously running send_arp for $OCF_RESKEY_ip"
1083		fi
1084		rm -f "$SENDARPPIDFILE"
1085	fi
1086	local ip_status=`ip_served`
1087	ocf_log info "IP status = $ip_status, IP_CIP=$IP_CIP"
1088
1089	if [ $ip_status = "no" ]; then
1090		: Requested interface not in use
1091		exit $OCF_SUCCESS
1092	fi
1093
1094	if [ -n "$IP_CIP" ] && [ $ip_status != "partial2" ]; then
1095		if [ $ip_status = "partial" ]; then
1096			exit $OCF_SUCCESS
1097		fi
1098		echo "-$IP_INC_NO" >$IP_CIP_FILE
1099		if [ "x$(cat $IP_CIP_FILE)" = "x" ]; then
1100			ocf_log info $OCF_RESKEY_ip, $IP_CIP_HASH
1101			i=1
1102			while [ $i -le $IP_INC_GLOBAL ]; do
1103				ocf_log info $i
1104				$IPADDR2_CIP_IPTABLES -D INPUT -d $OCF_RESKEY_ip -i $NIC -j CLUSTERIP \
1105					--new \
1106					--clustermac $IF_MAC \
1107					--total-nodes $IP_INC_GLOBAL \
1108					--local-node $i \
1109					--hashmode $IP_CIP_HASH
1110				i=`expr $i + 1`
1111			done
1112		else
1113			ip_del_if="no"
1114		fi
1115	fi
1116
1117	if [ "$ip_del_if" = "yes" ]; then
1118		delete_interface $OCF_RESKEY_ip $NIC $NETMASK
1119		if [ $? -ne 0 ]; then
1120			ocf_exit_reason "Unable to remove IP [${OCF_RESKEY_ip} from interface [ $NIC ]"
1121			exit $OCF_ERR_GENERIC
1122		fi
1123
1124		if ocf_is_true ${OCF_RESKEY_lvs_support}; then
1125			restore_loopback "$OCF_RESKEY_ip"
1126		fi
1127	fi
1128
1129	exit $OCF_SUCCESS
1130}
1131
1132ip_monitor() {
1133	# TODO: Implement more elaborate monitoring like checking for
1134	# interface health maybe via a daemon like FailSafe etc...
1135
1136	local ip_status=`ip_served`
1137	case $ip_status in
1138	ok)
1139		run_arp_sender refresh
1140		return $OCF_SUCCESS
1141		;;
1142	partial|no|partial2)
1143		exit $OCF_NOT_RUNNING
1144		;;
1145	*)
1146		# Errors on this interface?
1147		return $OCF_ERR_GENERIC
1148		;;
1149	esac
1150}
1151
1152# make sure that we have something to send ARPs with
1153set_send_arp_program() {
1154    ARP_SENDER=send_arp
1155    if [ -n "$OCF_RESKEY_arp_sender" ]; then
1156	case "$OCF_RESKEY_arp_sender" in
1157	send_arp)
1158	    check_binary $SENDARP
1159	;;
1160	iputils_arping)
1161	    check_binary arping
1162	;;
1163	libnet_arping)
1164	    check_binary arping
1165	;;
1166	ipoibarping)
1167	    check_binary ipoibarping
1168	;;
1169	*)
1170	    ocf_exit_reason "unrecognized arp_sender value: $OCF_RESKEY_arp_sender"
1171	    exit $OCF_ERR_CONFIGURED
1172	;;
1173	esac
1174	ARP_SENDER="$OCF_RESKEY_arp_sender"
1175    else
1176	if is_infiniband; then
1177	    ARP_SENDER=ipoibarping
1178	    if ! have_binary ipoibarping; then
1179	    	[ "$__OCF_ACTION" = start ] &&
1180		    ocf_log warn "using send_arp for infiniband because ipoibarping is not available (set arp_sender to \"send_arp\" to suppress this message)"
1181		check_binary $SENDARP
1182		ARP_SENDER=send_arp
1183	    fi
1184	fi
1185    fi
1186}
1187
1188ip_validate() {
1189    check_binary $IP2UTIL
1190    IP_CIP=
1191
1192    if [ -n "$OCF_RESKEY_network_namespace" ]; then
1193        OCF_RESKEY_network_namespace= exec $IP2UTIL netns exec "$OCF_RESKEY_network_namespace" "$0" "$__OCF_ACTION"
1194    fi
1195
1196    ip_init
1197
1198    set_send_arp_program
1199
1200    if [ -n "$IP_CIP" ]; then
1201        if have_binary "$IPTABLES_LEGACY"; then
1202            IPADDR2_CIP_IPTABLES="$IPTABLES_LEGACY"
1203        fi
1204        check_binary "$IPADDR2_CIP_IPTABLES"
1205        check_binary $MODPROBE
1206    fi
1207
1208# $BASEIP, $NETMASK, $NIC , $IP_INC_GLOBAL, and $BRDCAST have been checked within ip_init,
1209# do not bother here.
1210
1211    if ocf_is_true "$OCF_RESKEY_unique_clone_address" &&
1212	    ! ocf_is_true "$OCF_RESKEY_CRM_meta_globally_unique"; then
1213	ocf_exit_reason "unique_clone_address makes sense only with meta globally_unique set"
1214	exit $OCF_ERR_CONFIGURED
1215    fi
1216
1217    if ocf_is_decimal "$OCF_RESKEY_arp_interval" && [ $OCF_RESKEY_arp_interval -gt 0 ]; then
1218	:
1219    else
1220	ocf_exit_reason "Invalid OCF_RESKEY_arp_interval [$OCF_RESKEY_arp_interval]"
1221	exit $OCF_ERR_CONFIGURED
1222    fi
1223
1224    if ocf_is_decimal "$OCF_RESKEY_arp_count" && [ $OCF_RESKEY_arp_count -gt 0 ]; then
1225	:
1226    else
1227	ocf_exit_reason "Invalid OCF_RESKEY_arp_count [$OCF_RESKEY_arp_count]"
1228	exit $OCF_ERR_CONFIGURED
1229    fi
1230
1231    if [ -z "$OCF_RESKEY_preferred_lft" ]; then
1232	ocf_exit_reason "Empty value is invalid for OCF_RESKEY_preferred_lft"
1233	exit $OCF_ERR_CONFIGURED
1234    fi
1235
1236    if [ -n "$IP_CIP" ]; then
1237
1238	local valid=1
1239
1240	case $IP_CIP_HASH in
1241	sourceip|sourceip-sourceport|sourceip-sourceport-destport)
1242		;;
1243	*)
1244		ocf_exit_reason "Invalid OCF_RESKEY_clusterip_hash [$IP_CIP_HASH]"
1245		exit $OCF_ERR_CONFIGURED
1246		;;
1247	esac
1248
1249	if ocf_is_true ${OCF_RESKEY_lvs_support}; then
1250		ocf_exit_reason "LVS and load sharing not advised to try"
1251		exit $OCF_ERR_CONFIGURED
1252	fi
1253
1254	case $IF_MAC in
1255	[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])
1256		;;
1257	*)
1258		valid=0
1259		;;
1260	esac
1261
1262	if [ $valid -eq 0 ]; then
1263	  ocf_exit_reason "Invalid IF_MAC [$IF_MAC]"
1264	  exit $OCF_ERR_CONFIGURED
1265	fi
1266
1267    fi
1268}
1269
1270if ocf_is_true "$OCF_RESKEY_unique_clone_address"; then
1271    prefix=`echo $OCF_RESKEY_ip | awk -F. '{print $1"."$2"."$3}'`
1272    suffix=`echo $OCF_RESKEY_ip | awk -F. '{print $4}'`
1273    suffix=`expr ${OCF_RESKEY_CRM_meta_clone:-0} + $suffix`
1274    OCF_RESKEY_ip="$prefix.$suffix"
1275fi
1276
1277case $__OCF_ACTION in
1278meta-data)	meta_data
1279		;;
1280usage|help)	ip_usage
1281		exit $OCF_SUCCESS
1282		;;
1283esac
1284
1285ip_validate
1286
1287case $__OCF_ACTION in
1288start)		ip_start
1289		;;
1290stop)		ip_stop
1291		;;
1292status)		ip_status=`ip_served`
1293		if [ $ip_status = "ok" ]; then
1294			echo "running"
1295			exit $OCF_SUCCESS
1296		else
1297			echo "stopped"
1298			exit $OCF_NOT_RUNNING
1299		fi
1300		;;
1301monitor)	ip_monitor
1302		;;
1303validate-all)	;;
1304*)		ip_usage
1305		exit $OCF_ERR_UNIMPLEMENTED
1306		;;
1307esac
1308# vi:sw=4:ts=8:
1309