Для реализации функции автоматического переключения(отказоустойчивости) необходимо выполнить две задачи:
1. Протестировать состояние каналов и выбрать приоритетный
2. Произвести переключение
Первый пункт я давным-давно реализовал простеньким perl скриптом. Он
прошел долгий путь, мутировал и изменялся, поэтому вид имеет кривоватый
Для публикации здесь я его чуток причесал, но глобальных изменений не вносил.
Для работы скрипта необходим модуль Fcntl, установить его через CPAN можно так:
cpan install Fcntl
или так:
perl -MCPAN -e shell
и ввести install Fcntl
Скрипт check_chanel.pl (скачать):
#!/usr/bin/perl
###################################################################
#Name: check_chanel.pl
#Version: 1.0.4
#Created: Andrey Orlov
#Email: tangarus(a)gmail.com
#Web: http://www.tangarus.ru/
#Date: 02.2010
#Description:Автоматическое переключение каналов на linux роутере
####################################################################
use Fcntl qw(:DEFAULT :flock O_RDWR O_CREAT);
#Проверяем что запущен только один экземпляр скрипта
test_unique();
my @prov_name, @prov_if, @prov_gw, @prov_exec, @ping_res, @route_res, $all_work_exec, $num_prov, @hosts_to_ping, $ping_res_local;
#Что пингуем(рекомендую IP-адрес)
#Помним, что чем больше хостов пингуем - тем больше на это надо времени
@hosts_to_ping = ('213.180.204.8', '93.158.134.8'); #это разные IP-адреса www.ya.ru
#Сколько каналов(провайдеров)
$num_prov = 3;
#Приоритет провайдеров
@prio = (2,3,1);
#Команда выполняемая, если все провайдеры работают(пусто - не использовать)
$all_work_exec = '/opt/switch_to_balanced';
#Первый провайдер
$prov_name[1] = 'Inet'; #название провайдера
$prov_if[1] = 'eth1'; #интерфейс
$prov_gw[1] = '212.152.X.1'; #IP-адрес шлюза провайдера
$prov_exec[1] = '/opt/switch_to_inet'; #команда для переключения на этого провайдера
#Второй провайдер
$prov_name[2] = 'RialKom';
$prov_if[2] = 'eth1';
$prov_gw[2] = '80.X.255.129';
$prov_exec[2] = '/opt/switch_to_rialcom';
#Третий провайдер
$prov_name[3] = 'Gldn';
$prov_if[3] = 'eth3';
$prov_gw[3] = '62.X.7.241';
$prov_exec[3] = '/opt/switch_to_gldn';
#Пингуем всех
for($i=1;$i<=$num_prov;$i++){
print "ping $prov_name[$i] .... \n";
$ping_res[$i] = 1;
foreach $host_to_ping (@hosts_to_ping){
#Меняем маршрут
`/sbin/ip route replace $host_to_ping via $prov_gw[$i] dev $prov_if[$i]`;
#Чистим кеш, если надо
#`«/sbin/ip route flush cache`
$ping_res_local = `ping $host_to_ping -I $prov_if[$i] -c 5|grep \"100% packet loss\" -c`;
chomp($ping_res_local);
if ($ping_res_local ne 1){$ping_res[$i] = 0;};
};
};
#Проверяем через кого сейчас работаем
for($i=1;$i<=$num_prov;$i++){
$route_res[$i] = `/sbin/ip route|grep default|awk '{ print $3 }'|grep $prov_gw[$i] -c`;
chomp($route_res[$i]);
};
#Выводим результаты
print "\n\nResults:\n";
print "********* \n";
for($i=1;$i<=$num_prov;$i++){
print "Provider: $prov_name[$i] \n";
print "channel is down: $ping_res[$i] \n";
print "channel is current: $route_res[$i] \n";
print "********* \n";
};
$working_found = 0;
$all_work = 1;
foreach $prov (@prio){
if ($ping_res[$prov] eq 1){$all_work = 0;};
};
if (($all_work eq 1)&&($all_work_exec ne '')){
print "All providers work fine, switch to balanced mode\n";
system($all_work_exec);
$working_found = 1;
}else{
foreach $prov (@prio){
if ($ping_res[$prov] ne 1)
{
if ($route_res[$prov] ne 1)
{
print "Switch to $prov_name[$prov]\n";
system($prov_exec[$prov]);
$working_found = 1;
last;
}else{
print "Work trought $prov_name[$prov]\n";
$working_found = 1;
last;
};
};
};
};
if ($working_found eq 0)
{
print "Cannot found working channel!!! Nichego ne rabotaet!!! Ales kaput!!!\n";
};
exit();
sub test_unique(){
my @a=split /\//,$0;
my $lockfile="/var/run/".$a[$#a]."\.lock";
if (-e $lockfile){
if (sysopen(FH, $lockfile, O_WRONLY) && flock(FH, LOCK_EX|LOCK_NB)){
return 0;
} else {
print "Script $a[$#a] alredy started!!!\n"; exit(); }
}
sysopen(FH, $lockfile, O_WRONLY|O_CREAT) && flock(FH, LOCK_EX|LOCK_NB) || die $!;
return 0;
};
Сохраняем его как /opt/check_chanel.pl и добавляем права на запуск:
chmod ugo+x /opt/check_chanel.pl
Пример работы, основной канал упал, переключились на 2-ой:
ping Inet ....
ping RialKom ....
ping Gldn ....
Results (1=Yes, 0=No):
*********
Provider: Inet
channel is down: 0
channel is current: 0
*********
Provider: RialKom
channel is down: 1
channel is current: 1
*********
Provider: Gldn
channel is down: 0
channel is current: 0
*********
Switch to Inet
основной канал поднялся, переключаемся на него:
ping Inet ....
ping RialKom ....
ping Gldn ....
Results (1=Yes, 0=No):
*********
Provider: Inet
channel is down: 0
channel is current: 1
*********
Provider: RialKom
channel is down: 0
channel is current: 0
*********
Provider: Gldn
channel is down: 0
channel is current: 0
*********
Switch to RialKom
нормальный цикл работы на основном канале:
ping Inet ....
ping RialKom ....
ping Gldn ....
Results (1=Yes, 0=No):
*********
Provider: Inet
channel is down: 0
channel is current: 0
*********
Provider: RialKom
channel is down: 0
channel is current: 1
*********
Provider: Gldn
channel is down: 0
channel is current: 0
*********
Work trought RialKom
Приведу пример файла переключающего канал:
#!/bin/bash
/sbin/ip route delete default table main
/sbin/ip route delete default table T3
/sbin/ip route add default via 80.X.255.129 table main
/sbin/ip route add default via 80.X.255.129 table T3
/sbin/ip route flush cache
/sbin/iptables-restore /etc/iptables.nat
Вообще я планировал сначала описать создание multihomed роутера, а потом уже этот пост, но товарисчу Teacher'у срочно понадобилась инфа по автоматическому переключению. Так что скоро будет и указаный мануал.
Ну и напоследок, если все устраивает, добавляем в cron проверку каналов каждые 2 минуты:
*/2 * * * * /opt/check_chanel.pl
Спасибо за скрипт. Очень полезен (очень хотелось бы увидеть вылизанную обновлённую и дополненную версию ). Но у меня выдает следующие ошибки:
./check_chanel.pl
--------------------
Operator or semicolon missing before & at ./check_chanel.pl line 93.
Ambiguous use of & resolved as operator & at ./check_chanel.pl line 93.
Operator or semicolon missing before & at ./check_chanel.pl line 97.
Ambiguous use of & resolved as operator & at ./check_chanel.pl line 97.
syntax error at ./check_chanel.pl line 41, near «<»
syntax error at ./check_chanel.pl line 41, near «++)»
syntax error at ./check_chanel.pl line 44, near «);»
syntax error at ./check_chanel.pl line 56, near «<»
syntax error at ./check_chanel.pl line 56, near «++)»
syntax error at ./check_chanel.pl line 59, near «„channel is current: $route_res[$i] \n";»
syntax error at ./check_chanel.pl line 93, near «amp;»
syntax error at ./check_chanel.pl line 93, near «))»
syntax error at ./check_chanel.pl line 99, near «}»
Execution of ./check_chanel.pl aborted due to compilation errors.
--------------------
Как можно поправить?
От оригинального скрипта номер строки отличается на 2 строки вверх, т.е. не 99 а 97 например. (Добавлен 1 комменарий от себя).
Чего-то WordPress накосячил со спец символами.
Сейчас поправлю.
Вот ссылка на файл, пока борюсь с WP.
www.tangarus.ru/wp-conten...check_chanel.rar
[...] решение для Linux я уже описывал, и это можно сказать его «порт» на [...]
Спасибо, этот уже лучше Но всплыли 2 проблемы (не понятки?):
1. Когда скачал файл там было в конце каждой строки ^, пришлось долго и муторно убирать, видимо остатки виндового блокнота
2. Настроил для 2-х своих провайдеров:
приоритет 1,2
$prov_if[1] = 'eth2';
$prov_if[2] = 'eth1';
Но после чека пишет channel is current: 9 на основном (первом) провайдере, что за цифра 9 такая?
---------
Results:
*********
Provider: ProvMainETH2
channel is down: 0
channel is current: 9
*********
Provider: ProvReservETH1
channel is down: 1
channel is current: 0
*********
Provider:
channel is down: 0
channel is current:
*********
Switch to ProvMainETH2
--------
При ручном запуске комманды написаной в скрипте:
/sbin/route -n | grep eth2 -c
10
/sbin/route -n | grep eth1 -c
1
Не пойму откуда береться число 10 (в результате работы скрипта channel is current: 9, тоже не понятно откуда данная цифра). И будет ли она влият на сам сркипт. Хотелось бы что бы как у тебя было 2 истинных/ложных предположения 1 или 0
P.S. Контакты твои не нашел (хоят получить бы не мешало ). Приходится спамить тут.
tangarus (собака) gmail.com
/sbin/route -n | grep eth2 -c
Это ты считаешь количество вхождений «eth2» в выдаче «/sbin/route -n».
У меня написано «/sbin/route -n|grep $prov_gw[$i] -c», т.е. мы хотим узнать встречается-ли IP-адрес провайдера в выдаче «/sbin/route -n».
Помоему ты не то что надо написал в начале, вот тут:
#Первый провайдер
$prov_name[1] = 'Inet'; #название провайдера
$prov_if[1] = 'eth1'; #интерфейс
$prov_gw[1] = '212.152.X.1'; #IP-адрес шлюза провайдера
$prov_exec[1] = '/opt/switch_to_inet'; #команда для переключения на этого провайдера
Кстати, если у тебя какой-нибудь «хитрый» роутинг, то и выцеплять текущий gw надо будет похитрому.