Whamcloud - gitweb
LU-4278 libcfs: remove LWT
[fs/lustre-release.git] / lustre / scripts / lc_servip
1 #!/bin/bash
2 #
3 # lc_servip - script for verifying the service IP and the real
4 #             interface IP in a remote host are in the same subnet
5 #
6 ###############################################################################
7
8 # Usage
9 usage() {
10         cat >&2 <<EOF
11
12 Usage:  `basename $0` <service IPaddr> <hostname>
13         
14         service IPaddr          the IP address to failover
15         hostname                the hostname of the remote node
16
17 EOF
18         exit 1
19 }
20
21 # Check arguments
22 if [ $# -lt 2 ]; then
23         usage
24 fi
25
26 # Remote command
27 REMOTE=${REMOTE:-"ssh -x -q"}
28
29 # Check whether the reomte command is pdsh
30 is_pdsh() {
31         if [ "${REMOTE}" = "${REMOTE#*pdsh}" ]; then
32                 return 1
33         fi
34
35         return 0
36 }
37
38 #
39 # inSameIPsubnet serviceIPaddr interfaceIPaddr mask
40 #
41 # Given two IP addresses and a subnet mask determine if these IP
42 # addresses are in the same subnet. If they are, return 0, else return 1.
43 #
44 inSameIPsubnet() {
45         declare -i n
46         declare -ia mask 
47         declare -ia ip1 ip2             # IP addresses given
48         declare -i quad1 quad2          # calculated quad words
49
50         #
51         # Remove '.' characters from dotted decimal notation and save
52         # in arrays. i.e.
53         #
54         #       192.168.1.163 -> array[0] = 192
55         #                        array[1] = 168
56         #                        array[2] = 1
57         #                        array[3] = 163
58         #
59         let n=0
60         for quad in $(echo $1 | awk -F. '{print $1 " " $2 " " $3 " " $4}')
61         do
62                 ip1[n]=$quad
63                 let n=n+1
64         done
65
66         let n=0
67         for quad in $(echo $2 | awk -F. '{print $1 " " $2 " " $3 " " $4}')
68         do
69                 ip2[n]=$quad
70                 let n=n+1
71         done
72
73         let n=0
74         for quad in $(echo $3 | awk -F. '{print $1 " " $2 " " $3 " " $4}')
75         do
76                 mask[n]=$quad
77                 let n=n+1
78         done
79
80         #
81         # For each quad word, logically AND the IP address with the subnet
82         # mask to get the network/subnet quad word.  If the resulting
83         # quad words for both IP addresses are the same they are in the 
84         # same IP subnet.
85         #
86         for n in 0 1 2 3
87         do
88                 let $((quad1=${ip1[n]} & ${mask[n]}))
89                 let $((quad2=${ip2[n]} & ${mask[n]}))
90
91                 if [ $quad1 != $quad2 ]; then
92                         echo >&2 $"`basename $0`: Service IP address $1 and"\
93                                   "real interface IP address $2 are in"\
94                                   "different subnets!"
95                         return 1        # in different subnets
96                 fi
97         done
98
99         return 0        # in the same subnet, all quad words matched
100 }
101
102 #
103 # findInterface IPaddr hostname
104 #
105 # Given a target IP address and a hostname, find the interface in which 
106 # this address is configured.  If found return 0, if not return 1.  The
107 # interface name is returned to stdout.
108 #
109 findInterface() {
110         declare ret_line
111         declare line
112         declare intf
113         declare addr
114         declare state
115
116         declare target=$1
117         declare hostname=$2
118
119         while read ret_line
120         do
121                 set -- ${ret_line}
122                 is_pdsh && shift
123                 intf="$1"
124                 shift
125                 line="$*"
126
127                 while read line
128                 do
129                         if [ "$line" = "" ]; then       # go to next interface
130                                 continue 2
131                         fi
132
133                         set - $line
134                         addr=
135                         while [ $# -gt 0 ]; do
136                                 case $1 in
137                                 addr:*)
138                                         addr=${1##addr:}
139                                         if [ -n "$addr" -a "$addr" = "$target" ]
140                                         then
141                                                 echo $intf
142                                                 return 0
143                                         fi
144                                         ;;
145                                 esac
146                                 shift
147                         done
148                 done
149         done < <(${REMOTE} $hostname /sbin/ifconfig)
150
151         echo >&2 "`basename $0`: Cannot find the interface in which" \
152                   "$target is configured in the host $hostname!"
153         return 1
154 }
155
156 #
157 # findNetmask interface hostname
158 #
159 # Given an interface find the netmask addresses associated with it.
160 # Return 0 when found, else return 1. The netmask is returned to stdout.
161 #
162 findNetmask() {
163         declare ret_line
164         declare line
165         declare addr
166         declare target=$1
167         declare hostname=$2
168
169         while read ret_line
170         do
171                 set -- ${ret_line}
172                 is_pdsh && shift
173                 line="$*"
174
175                 set - $line
176
177                 while [ $# -gt 0 ]; do
178                         case $1 in
179                         Mask:*)
180                                 echo ${1##*:}   # return netmask addr
181                                 return 0 
182                                 ;;
183                         esac
184                         shift
185                 done
186         done < <(${REMOTE} $hostname /sbin/ifconfig $target)
187
188         echo >&2 "`basename $0`: Cannot find the netmask associated with" \
189                   "the interface $target in the host $hostname!"
190         return 1 
191 }
192
193 #
194 # check_srvIPaddr serviceIPaddr hostname
195 #
196 # Given a service IP address and hostname, check whether the service IP address
197 # and the real interface IP address of hostname are in the same subnet. 
198 # If they are, return 0, else return 1.
199 #
200 check_srvIPaddr() {
201         declare real_IPaddr
202         declare real_intf
203         declare netmask
204         declare srv_IPaddr=$1
205         declare hostname=$2
206
207         # Get the corresponding IP address of the hostname from /etc/hosts table
208         real_IPaddr=`egrep "[[:space:]]$hostname([[:space:]]|$)" /etc/hosts \
209                      | awk '{print $1}'`
210         if [ -z "$real_IPaddr" ]; then
211                 echo >&2 "`basename $0`: Hostname $hostname does not exist in" \
212                          "the local /etc/hosts table!"
213                 return 1
214         fi
215
216         if [ ${#real_IPaddr} -gt 15 ]; then
217                 echo >&2 "`basename $0`: More than one IP address line" \
218                          "corresponding to $hostname in the local"  \
219                          "/etc/hosts table!"
220                 return 1
221         fi
222
223         # Get the interface in which the real IP address is configured
224         real_intf=$(findInterface $real_IPaddr $hostname)
225         if [ $? -ne 0 ]; then
226                 return 1
227         fi
228         real_intf=${real_intf%%:*}
229
230         # Get the netmask address associated with the real interface
231         netmask=$(findNetmask $real_intf $hostname)
232         if [ $? -ne 0 ]; then
233                 return 1
234         fi
235
236         # Determine if the service IP address and the real IP address
237         # are in the same subnet
238         inSameIPsubnet $srv_IPaddr $real_IPaddr $netmask
239         if [ $? -ne 0 ]; then
240                 return 1
241         fi
242
243         return 0
244 }
245
246 # Check service IP address
247 if ! check_srvIPaddr $1 $2; then
248         exit 1
249 fi
250 exit 0