Subversion Repositories ALCASAR

Rev

Rev 1056 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log

Rev 1056 Rev 1068
Line 1... Line 1...
1
#!/bin/bash
1
#!/bin/bash
2
# $Id: alcasar-load_balancing.sh 1056 2013-03-26 21:46:36Z stephane $
2
# $Id: alcasar-load_balancing.sh 1068 2013-04-10 05:20:10Z franck $
3
 
3
 
4
# alcasar-load_balancing.sh
4
# Generic Load balancer for multiple WAN links - version 1.1 (04 Feb 2011)
5
# by BOUIJOUX Franck (3abTux) <3abtux@free.fr>
5
# (c) 2011 Pau Oliva Fora - http://pof.eslack.org
6
# This script is distributed under the Gnu General Public License (GPL)
-
 
7
 
6
#
8
# Équilibrage de charge sur 2 ou plusieurs liens internet (en cours d'expérimentation) 
-
 
9
# Définion des poids des routes   :  même poids --> alternance des connexions. Sinon le poids le plus faible est prioritaire
-
 
10
# Load balancing with 2 or more Internet links (experimental)
7
# Licensed under GPLv3 - for full terms see:
11
# Weitght of routes : same --> switch between link. The lowest weight gain the priority.
8
# http://www.gnu.org/licenses/gpl-3.0.html
12
 
9
#
13
WEIGHT1=1
-
 
14
WEIGHT2=1
-
 
-
 
10
# Adapted and debugged (adr et ping -S) by ALCASAR Team (3abtux@alcasar.net)
15
#WEIGHT3=3
11
# (c) 2013  3abtux - http://www.alcasar.net
16
 
12
#
17
# Définition des interfaces :
13
# Specify each WAN link in a separate column, example:
18
DEV1=${1-eth0}  # defaut eth0
-
 
19
DEV2=${2-eth0:1}  # defaut eth0 mais peut être autre chose :-)
14
# In this example we have 3 wan links (vlanXXX interfaces) attached to a single
20
#DEV3=${3-eth0:2}  # defaut eth0 mais peut être autre chose :-)
15
# physical interface because we use a vlan-enabled switch between the balancer
21
 
-
 
22
# Trouver les adresses pour chaque interface
16
# machine and the ADSL routers we want to balance. The weight parameter should
23
IP1=`ifconfig $DEV1 | grep inet | awk '{ print $2 }' | awk -F: '{ print $2 }'`
17
# be kept to a low integer, in this case the ADSL line connected to vlan101 and
24
IP2=`ifconfig $DEV2 | grep inet | awk '{ print $2 }' | awk -F: '{ print $2 }'`
18
# vlan102 is 4Mbps and the ADSL line connected to vlan100 is 8Mbps (twice fast)
25
#IP3=`ifconfig $DEV3 | grep inet | awk '{ print $2 }' | awk -F: '{ print $2 }'`
19
# so the WEIGHT value in vlan100 is 2 because it is two times faster.
-
 
20
#
-
 
21
#
-
 
22
# Modified by ALCASAR team :
-
 
23
 
26
 
24
 
-
 
25
###############################
27
# Trouver les passerelles pour chaque interface { ne fonctionne pas bien avec une seule interface } --> forcer les passerelles !
26
# MAIN PARAMETERs Configuration
28
#GW1=`route -n | grep $DEV1 | grep '^0.0.0.0' | awk '{ print $2 }'`
27
###############################
29
#GW2=`route -n | grep $DEV2 | grep '^0.0.0.0' | awk '{ print $2 }'`
28
# enable link failover watchdog? set to "yes" or "no".
30
GW1=192.168.1.1
29
WATCHDOG="yes"
31
GW2=192.168.1.6
30
SLEEP="30"
32
#GW3=192.168.1.6
-
 
33
 
31
 
34
echo "Acces internet depuis $DEV1: IP=$IP1  par la GW=$GW1"
32
# space separated list of public IPs to ping in watchdog mode
35
echo "            et depuis $DEV2: IP=$IP2  par la GW=$GW2"
-
 
36
#echo "            et depuis $DEV3: IP=$IP3  par la GW=$GW3"
33
# set this to some public ip addresses pingable and always on.
37
 
-
 
38
# Mise en place des routes 
34
TESTIPS="8.8.8.8 192.0.32.10"
39
 
35
 
40
# Tester si les tables existent sinon les créer
36
# set to 1 when testing, set to 0 when happy with the results
41
if [ -z "`cat /etc/iproute2/rt_tables | grep '^252'`" ] ; then
-
 
42
        echo "252       rt_dev1" >> /etc/iproute2/rt_tables
-
 
43
fi
37
VERBOSE=1
44
 
38
 
45
if [ -z "`cat /etc/iproute2/rt_tables | grep '^251'`" ] ; then
-
 
46
        echo "251       rt_dev2" >> /etc/iproute2/rt_tables
-
 
47
fi
-
 
48
#if [ -z "`cat /etc/iproute2/rt_tables | grep '^250'`" ] ; then
-
 
49
#       echo "250       rt_dev3" >> /etc/iproute2/rt_tables
-
 
50
#fi
-
 
51
 
-
 
52
 
-
 
53
# Tables de routage
-
 
54
ip route add default via $GW1 table rt_dev1
-
 
55
ip route add default via $GW2 table rt_dev2
-
 
56
#ip route add default via $GW3 table rt_dev3
-
 
57
 
-
 
58
# Création des règles
39
# CONFIGURATION ENDS HERE
59
ip rule add from $IP1 table rt_dev1
-
 
60
ip rule add from $IP2 table rt_dev2
-
 
61
#ip rule add from $IP3 table rt_dev3
40
###############################
62
 
-
 
63
# Effacer la route par défaut existante
-
 
64
ip route del default
-
 
65
if [ ! -z "`ip route show table main | grep 'nexthop'`" ] ; then
-
 
66
        ip route del default scope global
-
 
67
fi
-
 
68
 
41
 
69
# Alterne les liens basés sur chaque route
-
 
70
ip route add default scope global nexthop via $GW1 dev $DEV1 weight $WEIGHT1 \
-
 
71
                                nexthop via $GW2 dev $DEV2 weight $WEIGHT2
-
 
72
#                               nexthop via $GW3 dev $DEV3 weight $WEIGHT3 
-
 
73
 
42
 
74
 
43
 
-
 
44
if [ $(whoami) != "root" ]; then
-
 
45
        echo "You must be root to run this!" ; echo ; exit 1
-
 
46
fi
-
 
47
 
-
 
48
# Adapter for ALCASAR project
-
 
49
CONF_FILE="/usr/local/etc/alcasar.conf"
-
 
50
 
-
 
51
# Virtual interfaces creating
-
 
52
function create_eth () {
-
 
53
	routecmd="ip route replace default scope global"
-
 
54
	NBIFACE=`grep "^WAN" $CONF_FILE | wc -l`	# Nbre interfaces virtuelles
-
 
55
	i=0
-
 
56
	while [ $i -le $NBIFACE ]
-
 
57
	do
-
 
58
		INT="WAN$i"
-
 
59
		echo $INT
-
 
60
		ACTIVE=`grep "$INT=" $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $1}'`	# Active
-
 
61
		WT=`grep "$INT=" $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $5}'`		# WEIGHT
-
 
62
		WT=${WT:-1}
-
 
63
		IP=`grep "$INT=" $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $3}' | cut -d"/" -f1`	# @IP
-
 
64
 
-
 
65
		if [ $i -ne 0 ]; then
-
 
66
			[ -e /etc/sysconfig/network-scripts/ifcfg-eth0:$i ] && ifdown eth0:$i && rm -f /etc/sysconfig/network-scripts/ifcfg-eth0:$i
-
 
67
			IFACE=`grep "$INT=" $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $2}'`	# IFACE
-
 
68
			IP_NET=`grep "^$INT=" $CONF_FILE | awk -F'"' '{print $2}' | awk -F, '{ print $3}'`	# IP
-
 
69
			NET="`ipcalc -n $IP_NET | cut -d"=" -f2`/`ipcalc -p $IP_NET|cut -d"=" -f2`"
-
 
70
			GW=`grep "$INT=" $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $4}'`		# @GW
-
 
71
			MTU=`grep "$INT=" $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $6}'`	# MTU
-
 
72
 
-
 
73
			# Config eth0:$i (Internet)
-
 
74
			cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-eth0:$i
-
 
75
DEVICE=$IFACE
-
 
76
BOOTPROTO=static
-
 
77
IPADDR=`echo $IP | cut -d"/" -f1`
-
 
78
NETMASK=`ipcalc -m $IP_NET | cut -d= -f2`
-
 
79
NETWORK=`ipcalc -n $IP_NET | cut -d= -f2`
-
 
80
MTU=$MTU
-
 
81
ONBOOT=yes
-
 
82
NOZEROCONF=yes
-
 
83
MII_NOT_SUPPORTED=yes
-
 
84
IPV6INIT=no
-
 
85
IPV6TO4INIT=no
-
 
86
ACCOUNTING=no
-
 
87
USERCTL=no
-
 
88
EOF
-
 
89
			echo "ifup eth0:$i"
-
 
90
			ifup eth0:$i
-
 
91
			NET="`ipcalc -n $IP_NET | cut -d"=" -f2`/`ipcalc -p $IP_NET|cut -d"=" -f2`"
-
 
92
		else
-
 
93
			IFACE="eth0"
-
 
94
			IP_NET=`grep "^PUBLIC_IP=" $CONF_FILE | awk -F'=' '{print $2}'`			# IP/MSK
-
 
95
			IP=`grep "^PUBLIC_IP=" $CONF_FILE | awk -F= '{ print $2 }' | cut -d"/" -f1`	# @IP
-
 
96
			GW=`grep "^GW=" $CONF_FILE | awk -F= '{print $2}'`				# @GW
-
 
97
#			MTU=`grep "^PUBLIC_MTU=" $CONF_FILE | awk -F= '{print $2}'`			# MTU
-
 
98
		fi # End
-
 
99
 
-
 
100
		NET="`ipcalc -n $IP_NET | cut -d"=" -f2`/`ipcalc -p $IP_NET|cut -d"=" -f2`"
-
 
101
		if [ "$PARAM" == "add" ]; then	
-
 
102
			set -x
-
 
103
			table=$(($i + 1))
-
 
104
			ip route ${PARAM} ${NET} dev ${IFACE} src ${IP} table $table
-
 
105
			ip route ${PARAM} default via ${GW} table $table
-
 
106
			ip rule ${PARAM} from ${IP} table $table
-
 
107
			set +x
-
 
108
		fi
-
 
109
		echo "	Iface: ${IFACE}"
-
 
110
		echo "	IP: ${IP}"
-
 
111
		echo "	IP_NET: ${IP_NET}"
-
 
112
		echo "	NET: ${NET}"
-
 
113
		echo "	GW: ${GW}"
-
 
114
		echo "	Weight: ${WT}"
-
 
115
		echo "	MTU : ${MTU}"
-
 
116
		echo
-
 
117
		routecmd="${routecmd} nexthop via ${GW} dev ${IFACE} weight ${WT}"
-
 
118
		i=$(($i + 1))
-
 
119
	done # End While
-
 
120
 
-
 
121
	if [ "$PARAM" == "add" ]; then	
-
 
122
		echo "[] Balanced routing:"
-
 
123
		# suppress default route
-
 
124
		ip route del default scope global
-
 
125
		set -x
-
 
126
		${routecmd}
-
 
127
		set +x
-
 
128
		echo
-
 
129
	fi
-
 
130
	
-
 
131
} # end create_eth
-
 
132
 
-
 
133
###########################
-
 
134
# Fonction virtual Interfaces deleting
-
 
135
###########################
-
 
136
delete_eth () {
-
 
137
	IFACE_COUNT=`ls -l /etc/sysconfig/network-scripts/ifcfg-eth0:* | wc -l`
-
 
138
	echo $IFACE_COUNT
-
 
139
	while [ $IFACE_COUNT -ne 0 ]
-
 
140
	do
-
 
141
		i=$IFACE_COUNT	
-
 
142
		echo "ifdown eth0:$i"
-
 
143
		ifdown eth0:$i
-
 
144
		rm -f /etc/sysconfig/network-scripts/ifcfg-eth0:$i
-
 
145
		IFACE_COUNT=$(($IFACE_COUNT - 1))
-
 
146
	done
-
 
147
	ip route del default scope global
-
 
148
#	ip route add default gw 192.168.1.1
-
 
149
}
-
 
150
	
-
 
151
 
-
 
152
# do not modify below this line unless you know what you're doing :)
-
 
153
function getvalue() {
-
 
154
        index=$1
-
 
155
        VAR=$2
-
 
156
 
-
 
157
        n=1
-
 
158
        for f in ${VAR} ; do
-
 
159
                if [ "${n}" == "${index}" ]; then
-
 
160
                        echo "$f"
-
 
161
                        break
-
 
162
                fi
-
 
163
                n=$(($n++))
-
 
164
        done
-
 
165
}
-
 
166
 
-
 
167
######################
75
# Purge le cache
168
# Fonction de FailOver
-
 
169
######################
-
 
170
function failover () {
-
 
171
 
-
 
172
	echo "[] Watchdog started"
-
 
173
	# 0 == all links ok, 1 == some link down
-
 
174
	STATE=0
-
 
175
	
-
 
176
	DOWNCOUNT_BAK=0
-
 
177
	DOWN_BAK=""
-
 
178
	NBIFACE=`grep "^WAN" $CONF_FILE | wc -l`	# Nbre interfaces virtuelles
-
 
179
	echo "Nombre interfaces =  "$NBIFACE
-
 
180
	WANIFACE[0]="eth0"	# eth0 par défaut
-
 
181
	c=0
-
 
182
	while [ $c -le $NBIFACE ]; do
-
 
183
		ITH=(`grep "WAN$c=" $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $2}'`)	# IFACE
-
 
184
		echo $ITH
-
 
185
		WANIFACE="${WANIFACE} $ITH"
-
 
186
		echo $WANIFACE
-
 
187
		c=$(($c + 1))
-
 
188
	done
-
 
189
	echo "Liste des interfaces : "${WANIFACE[*]}
-
 
190
	# Failover test
-
 
191
	while : ; do
-
 
192
	
-
 
193
		if [ $VERBOSE -eq 1 ]; then
-
 
194
			echo "[] Sleeping, state=$STATE"
-
 
195
		fi
-
 
196
		sleep $SLEEP
-
 
197
	
-
 
198
		IFINDEX=1
-
 
199
		DOWN=""			# liste des interfaces down
-
 
200
		DOWNCOUNT=0		# nombre d'interface down
-
 
201
		for iface in $WANIFACE ; do
-
 
202
			COUNT=0		# compteur de test
-
 
203
			FAIL=0		# Nombre de fois down
-
 
204
			# Recup de l'adresse IP dynamiquement          A tester avec le tableau ... ip=${ETH[$i:2]} basé sur iface=${ETH[$i:1]}
-
 
205
			IP=`ifconfig $iface |grep "inet adr" |cut -f 2 -d ":" |awk '{print $1}'`
-
 
206
			if [ $i -ne 0 ]; then
-
 
207
				GW=`grep "$iface," $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $4}'`		# @GW
-
 
208
				WT=`grep "$iface," $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $5}'`		# @WT
-
 
209
			else
-
 
210
				GW=`grep "^GW=" $CONF_FILE | awk -F= '{print $2}'`			# @GW
-
 
211
			fi	
-
 
212
			for TESTIP in $TESTIPS ; do
-
 
213
				COUNT=$(($COUNT + 1))
-
 
214
				ping -W 3 -I $IP -c 1 $TESTIP > /dev/null 2>&1
-
 
215
#				ping -W 3 -I $IP -c 1 $TESTIP
-
 
216
				# Si ping de la première adresse --> ok  --> stop du test pour l'interface testée
-
 
217
				if [ $? -eq 0 ]; then
-
 
218
					break
-
 
219
				else 
-
 
220
					# sinon on compte une erreur
-
 
221
					FAIL=$(($FAIL + 1))
-
 
222
				fi
-
 
223
			done # End of test sur un serveur Internet
-
 
224
			# Affichage du nombre de down
-
 
225
			echo "FAIL=$FAIL"
-
 
226
			# Si nombre de fois down = nombre de tests -->  Iface down --> log dans fichier log avec l'heure
-
 
227
			if [ $FAIL -eq $COUNT ]; then
-
 
228
				echo "`date +%F-%Hh%mm%Ss` : [WARN] $iface is down!"
-
 
229
				# Si etat différent de 1 (déjà tombé) --> changement de l'état général en default
-
 
230
				if [ $STATE -ne 1 ]; then
-
 
231
					echo "Switching state $STATE -> 1"
-
 
232
					STATE=1
-
 
233
				fi
-
 
234
				# Rajout de l'iface dans la liste des interfaces down
-
 
235
				DOWN="${DOWN} $IFINDEX"
-
 
236
				echo "DOWN=$DOWN"
-
 
237
				# Nombre d'interface down
-
 
238
				DOWNCOUNT=$(($DOWNCOUNT + 1))
-
 
239
				echo "DOWNCOUNT=$DOWNCOUNT"
-
 
240
			fi
-
 
241
			IFINDEX=$(($IFINDEX + 1))
-
 
242
			echo "IFINDEX =$IFINDEX"
-
 
243
		done # End Test Interface in WANIFACE
-
 
244
 
-
 
245
		#  0 Passerelle down et état précédent différent (retour à la normale)) --> mise à la normale des passerelles 
-
 
246
#		if [ $DOWNCOUNT -eq 0 ] && [ $DOWNCOUNT -ne $DOWNCOUNT_BAK ]; then
-
 
247
		if [ $DOWNCOUNT -eq 0 ] ; then
-
 
248
			if [ $STATE -eq 1 ]; then
-
 
249
				echo
-
 
250
				echo "[] All links up and running :)"
-
 
251
				set -x
-
 
252
				${routecmd}
-
 
253
				set +x
-
 
254
				# Changement de l'état en normal
-
 
255
				STATE=0
-
 
256
				echo "Switching state 1 -> 0"
-
 
257
			fi # End retour etat normal
-
 
258
			# if no interface is down, go to the next cycle
-
 
259
			continue
-
 
260
		# cas ou au moins une passerelle down mais état identique au précédent Test --> rien à changer
-
 
261
		else
-
 
262
			if [ "$DOWN_BAK" == "$DOWN" ]; then
-
 
263
			echo "DOWN_BAK == DOWN = $DOWN"
-
 
264
				continue	# --> état identique test precedent --> boucle suivante
-
 
265
		# cas ou au moins une passerelle down mais état différent de test précédent --> remplacement par nouvelle règle
-
 
266
			else
-
 
267
				cmd="ip route replace default scope global"
-
 
268
				IFINDEX=1
-
 
269
				suffix=""
-
 
270
				# Pour chaque interface --> traitement et application de la règle de routage
-
 
271
				for iface in $WANIFACE ; do
-
 
272
					echo "-------------------------"
-
 
273
					echo "iface=$iface"
-
 
274
					echo "Index = " $IFINDEX
-
 
275
					FAILIF=0
-
 
276
					# Pour chaque interface down --> 
-
 
277
					echo "Interfaces DOWN = $DOWN"
-
 
278
					for lnkdwn in $DOWN ; do
-
 
279
						echo "LINKDOWN = "$lnkdown
-
 
280
						if [ $lnkdwn -eq $IFINDEX ]; then
-
 
281
							FAILIF=1
-
 
282
							break			
-
 
283
						else
-
 
284
							continue
-
 
285
						fi
-
 
286
					done # End linkdown in DOWN
-
 
287
					# Interface en etat normal --> rajout de la règle en mode nexthop
-
 
288
					if [ $FAILIF -eq 0 ]; then
-
 
289
						IP=`ifconfig $iface |grep "inet adr" |cut -f 2 -d ":" |awk '{print $1}'`
-
 
290
						if [ $iface != "eth0" ]; then
-
 
291
							GW=`grep "$iface," $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $4}'`		# @GW
-
 
292
							WT=`grep "$iface," $CONF_FILE | awk -F'"' '{ print $2 }' | awk -F, '{ print $5}'`		# @GW
-
 
293
						else
-
 
294
							GW=`grep "^GW=" $CONF_FILE | awk -F= '{print $2}'`			# @GW
-
 
295
						fi	
-
 
296
						echo "GW=$GW"
-
 
297
						echo "WT=$WT"
-
 
298
						echo "suffix=$sufix"
-
 
299
						suffix="${suffix} nexthop via ${GW} dev ${iface} weight ${WT:-1}"
-
 
300
					fi # End interface = noFAIL
-
 
301
					IFINDEX=$(($IFINDEX + 1))
-
 
302
				done # End  iface IN WANIFACE
-
 
303
				# Commande globale
-
 
304
				cmd="ip route replace default scope global $suffix"
-
 
305
			
-
 
306
				if [ $VERBOSE -eq 1 ]; then
-
 
307
					set -x
-
 
308
			#		echo "Avec commentaire : " ${cmd}
-
 
309
					${cmd}
-
 
310
					set +x
-
 
311
					echo
-
 
312
				else
-
 
313
					${cmd} 2>/dev/null
-
 
314
					echo ${cmd}
-
 
315
				fi # end Application de la commande de routage globale
-
 
316
			fi #
-
 
317
			DOWN_BAK=$DOWN	# Enregistrement de l'etat
-
 
318
		fi # End 
-
 
319
	done
-
 
320
} # End of Failover
-
 
321
 
-
 
322
 
-
 
323
#################
-
 
324
# Main
-
 
325
#################
-
 
326
 
-
 
327
echo "[] Load balancer for multiple WAN interfaces - v2.1"
-
 
328
echo "[] (c) 2011 Pau Oliva Fora <pof> @eslack.org"
-
 
329
echo "[] (c) 2013 3abtux ALCASAR  <3abtux> @alcasar.net"
-
 
330
echo
-
 
331
 
-
 
332
case $1 in
-
 
333
	create) 
-
 
334
		create_eth  		
-
 
335
	;;
-
 
336
	delete) 
-
 
337
		delete_eth  		
-
 
338
	;;
-
 
339
	fail) 
-
 
340
		failover 		
-
 
341
	;;
-
 
342
	start) 
-
 
343
		PARAM="add"
-
 
344
		create_eth  		
-
 
345
		if [ $WATCHDOG != "yes" ]; then
-
 
346
			exit 0
-
 
347
		fi
76
ip route flush cache
348
		ip route flush cache
-
 
349
#		RETVAL=$?
-
 
350
#		echo
-
 
351
#		[ $RETVAL -eq 0 ] && touch /var/lock/subsys/alcasar-load_balancing
-
 
352
		touch /var/lock/subsys/alcasar-load_balancing
-
 
353
		failover
-
 
354
	;;
-
 
355
	stop) 
-
 
356
		PARAM="del"
-
 
357
		prog="alcasar-load_balancing.sh"
-
 
358
	        gprintf $"Shutting down $prog: "
-
 
359
		killproc $prog
-
 
360
		RETVAL=$?
-
 
361
	        echo
-
 
362
	        [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/alcasar-load_balancing
-
 
363
		return $RETVAL
-
 
364
		ip route
-
 
365
	;;
-
 
366
	*) 
-
 
367
		echo "Usage: $0 [start|stop|create|delete]" ; echo ; exit 1
-
 
368
	;;
-
 
369
esac
77
 
370
 
78
# Fin de alcasar-load_balancing.sh
-
 
79
 
371
exit 0
-
 
372