9 พฤศจิกายน 2554

วิธี Load Balance เน็ต 2สายใน Endian Firewall2.4 ด้วย bash shell script

ปัญหา จากวิธีเดิมที่เคยใช้ EFW 2.4.1 ด้วยการแก้ไขไฟล์ /var/efw/inithooks/start.local ข้อเสียของวิธีนี้คือ.. ถ้าเน็ตเส้นใดเส้นนึงหลุดเน็ตบางเครื่องจะใช้ไม่ได้

วิธีการเซ็ท load balance สำหรับ uplink แบบ PPPoE (router bridge mode) แบบง่ายๆ เร็วๆ
ไฟล์ /var/efw/inithooks/start.local
#!/bin/sh
route del default
ip route add default equalize nexthop dev ppp0 weight 1 nexthop dev ppp1 weight 1  
exit 0

แล้วตั้งเวลาใน etc/crontab ให้รัน start.local ทุก 15นาที
*/15 * * * * /var/efw/inithooks/start.local

จะได้ ip route ออกเน็ตสองเส้นทาง
default equalize 
        nexthop dev ppp0 weight 1
        nexthop dev ppp1 weight 1

ใช้เวลาแปปเดียวแต่เสียความสามารถในการ Backup/Failover ไป ส่วนอีกวิธีที่แน่นอนกว่า..

ทำ load balance ด้วย Linux Bash script 
ผมเปลี่ยนมาใช้วิธีนี้นานแล้วไม่เคยมีปัญหาอีกเลย

กรณีต่อแบบ PPPoE uplink: เซ็ท adsl router แบบ bridge mode ใช้ efw เป็นตัว connect
main uplink : eth0 -> ppp0
uplink1 : eth2 -> ppp1

*Notice* ในสคริปท์ต้องระบุ interface ที่ใช้ คือ eth0, eth2, ppp0, ppp1 ให้ตรงกับชื่อในเซอฟเวอร์จริง

1. สร้างไฟล์สคริปท์ใน /usr/share/balance.sh กำหนด Chmod 755 (-rwxr-xr-x) 

text editor แล้วแต่ชอบแล้วค่อย WinSCP อัพโหลดเข้าไป
# ---  2 Wan loadbalance ---
#!/bin/bash
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
PROG="balance2WAN"
PROGDIR="/usr/local/sbin"
# Configuration Variables
# ----- Begin Of Configuration -----
# IP Address to ping.
# www.avira.com
CHECKHOST1=62.146.210.54
# www.yahoo.com
CHECKHOST2=98.137.149.56
# www.google.com
CHECKHOST3=209.85.175.104
# www.yahoo.co.th
CHECKHOST4=203.84.219.114
# www.sourceforge.net
CHECKHOST5=216.34.181.60
# Variables hold total ping fail of each eth
CHECKNOTRETVAL1=0
CHECKNOTRETVAL2=0
# Variables hold the exceed ping fail number
CHECKWEIGHT=3
# Variables hold ping timeout in seconds
TIMEOUT=3
# Variables hold link status used for determined in program.
LASTLINKSTATUS1=1
LASTLINKSTATUS2=1
# Variables hold link status used for report purpose.
CHECKRESAULT1=UP
CHECKRESAULT2=UP
# Broadband providers name; used for report purpose.
NAME1=TrueADSL
NAME2=TOT
# Ethernet interfaces (eth ); used for determined in program.
EXTIF1=eth0
EXTIF2=eth2
# Relative weights of routes. Keep this to a integer value.
# If WEIGHT1=1 WEIGHT2=1 ; Balance WEIGHT1:WEIGHT2 is 50 : 50
# If WEIGHT1=2 WEIGHT2=1 ; Balance WEIGHT1:WEIGHT2 is 2/3 ( 66.67 ) : 1/3 ( 33.33 )
WEIGHT1=1
WEIGHT2=1
# Log file for routing status report
CHECKGATEWAYLOG=/var/log/gatewaystatus
# ----- End Of Variable Configuration -----
# ----- Begin Of get IP and Gateway from each eth -----
# Do not change anything below this line excepted use ppp0
# If use ppp0 ; Get IP addresses from ppp0 devices by
IP1=`ifconfig ppp0 | grep inet | awk '{ print $2 }' | awk -F: '{ print $2 }'`
IP2=`ifconfig ppp1 | grep inet | awk '{ print $2 }' | awk -F: '{ print $2 }'`
#IP1=`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`
#IP2=`ifconfig eth2 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`

# Define gateway addresses by replace last segment of each eth IP with Router IP
# ENDGW is the last segment of Router IP
ENDGW1=1
ENDGW2=1
# Do not change anything below this line excepted use ppp0
# If EXTIF1(eth1)used ppp0 , gateway is same as the ppp0 IP
# GW1=$
GW1=$IP1
GW2=$IP2
#GW1=${IP1%.*}.$ENDGW1
#GW2=${IP2%.*}.$ENDGW2
     
# ----- End Of read IP and Gateway from each eth -----
# Check wan1 link status
for CHECKHOSTS in {$CHECKHOST1,$CHECKHOST2,$CHECKHOST3,$CHECKHOST4,$CHECKHOST5}; do
      ping -W $TIMEOUT -I $IP1 -c 1 $CHECKHOSTS > /dev/null  2>&1
      RETVAL=$?
      if [ $RETVAL -ne 0 ]; then
          CHECKNOTRETVAL1=`expr $CHECKNOTRETVAL1 + 1`
      fi
done
if [ $CHECKNOTRETVAL1 -ge $CHECKWEIGHT ]; then
   LASTLINKSTATUS1=1
   CHECKRESAULT1=DOWN
else
   LASTLINKSTATUS1=0
   CHECKRESAULT1=UP
fi
# Check wan2 link status
for CHECKHOSTS in {$CHECKHOST1,$CHECKHOST2,$CHECKHOST3,$CHECKHOST4,$CHECKHOST5}; do
     ping -W $TIMEOUT -I $IP2 -c 1 $CHECKHOSTS > /dev/null  2>&1
     RETVAL=$?
     if [ $RETVAL -ne 0 ]; then
        CHECKNOTRETVAL2=`expr $CHECKNOTRETVAL2 + 1`
     fi
done
if [ $CHECKNOTRETVAL2 -ge $CHECKWEIGHT ]; then
   LASTLINKSTATUS2=1
   CHECKRESAULT2=DOWN
else
   LASTLINKSTATUS2=0
   CHECKRESAULT2=UP
fi
# Send WAN Status to log file
date +'-------------------------(%D %T)-------------------------' >> $CHECKGATEWAYLOG
echo ---------------------------------------------------------------------  >> $CHECKGATEWAYLOG
echo Line $NAME1 IP $IP1 GW $GW1 is $CHECKRESAULT1 : Ping fail $CHECKNOTRETVAL1 OF 5   >> $CHECKGATEWAYLOG
echo Line $NAME2 IP $IP2 GW $GW2 is $CHECKRESAULT2 : Ping fail $CHECKNOTRETVAL2 OF 5   >> $CHECKGATEWAYLOG
echo ---------------------------------------------------------------------  >> $CHECKGATEWAYLOG
# Custom routing base on WAN status
if [[ $LASTLINKSTATUS1 -eq 1 && $LASTLINKSTATUS2 -eq 0 ]]; then
   echo - Routing using 1 WAN - $NAME2>> $CHECKGATEWAYLOG
   echo ---------------------------------------------------------------------  >> $CHECKGATEWAYLOG
   ip route flush cache     
   ip route replace default scope global via $GW2 dev $EXTIF2
   ip route show | awk '{print}' >> $CHECKGATEWAYLOG
elif [[ $LASTLINKSTATUS1 -eq 0 && $LASTLINKSTATUS2 -eq 1 ]]; then
   echo - Routing using 1 WAN - $NAME1 >> $CHECKGATEWAYLOG
   echo ---------------------------------------------------------------------  >> $CHECKGATEWAYLOG
   ip route flush cache     
   ip route replace default scope global via $GW1 dev $EXTIF1
   ip route show | awk '{print}' >> $CHECKGATEWAYLOG
elif [[ $LASTLINKSTATUS1 -eq 0 && $LASTLINKSTATUS2 -eq 0 ]]; then
   echo - Routing using 2 WAN - $NAME1, $NAME2 >> $CHECKGATEWAYLOG
   echo ---------------------------------------------------------------------  >> $CHECKGATEWAYLOG
   ip route flush cache
   ip route replace default scope global nexthop via $GW1 dev $EXTIF1 weight $WEIGHT1 nexthop via $GW2 dev $EXTIF2 weight $WEIGHT2
   ip route show | awk '{print}' >> $CHECKGATEWAYLOG
fi
echo ===================================================================== >> $CHECKGATEWAYLOG
# ---  End balancing ---

กรณีต่อแบบ Ethernet Static : fix ip ใช้ adsl router เป็นตัว connect

main uplink : eth0 192.168.1.x -> adsl router1 192.168.1.1
uplink1 : eth2 192.168.2.x -> adsl router2 192.168.2.1

แก้ตัวแปร IP1, IP2 และ GW1, GW2

IP1=`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`
IP2=`ifconfig eth2 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`

GW1=${IP1%.*}.$ENDGW1
GW2=${IP2%.*}.$ENDGW2


2. แก้ไฟล์ /etc/crontab ให้รัน /usr/share/balance.sh ทุก 5นาที
*/5 * * * * /usr/share/balance.sh

3. ทดสอบโดยปิด router หรือดึงสายเน็ตเส้นใดเส้นหนึ่งออก สั่งรัน
# /usr/share/balance.sh
# ip route show

default route จะเลือกใช้เฉพาะ eth หรือ ppp ที่ยังเชื่อมต่อได้ ถึงจะหลุดไปเส้นนึงก็ยังใช้งานอินเตอร์เน็ตได้ตามปกติ

อ้างอิง :
จาก Repของคุณ SwanGhost ใน thaiadmin.org 
Advanced Bash-Scripting Guide http://tldp.org/LDP/abs/html/
Blog linux.sothorn.org อันนี้น่าจะเป็นต้นฉบับ Endian Firewall 2.2 RC2 Load Balance

2 ความคิดเห็น:

  1. สอบถามหน่อยครับ
    ตอนนี้ผมใช้ EFW 2.5.1 อยู่ มีขา red 2 ขา
    ผมต้องการให้ EFW เช็คว่าถ้า ขา green วิ่งไป facebook ให้ไปวิ่งไป red 2
    ถ้าเว็บทั่วไปวิ่งไป red 1 ต้องปรับยังไงครับ

    ตอบลบ
  2. แล้วจะโหลด file balance.sh ได้จากไหนครับ

    ตอบลบ