- PVSM.RU - https://www.pvsm.ru -
В организациях, использующих арендованные у операторов связи каналы передачи данных VPN/Интернет для построения корпоративной филиальной сети, рано или поздно может возникнуть ситуация, когда внезапно выясняется, что каналы до некоторых удаленных подразделений не соответствуют заявленным требованиям по полосе пропускания, либо при незначительной загрузке каналов появляются потери, влияющие на качество работы сетевых сервисов.
При этом система мониторинга исправно мониторит доступность каналов, потери на них, задержку, но вследствие того, что каналы связи не всегда загружены трафиком, особенно резервные каналы, она не может своевременно выявить все отклонения их параметров от согласованных с операторами связи. Для таких целей требуется проведение периодического нагрузочного тестирования каналов, в результате которого производится проверка потерь на канале при одновременной его загрузке трафиком, утилизирующим канал практически до максимальных значений полосы пропускания, с последующим контролем объема принятого трафика удаленным маршрутизатором. Хочу поделиться своими наработками в части автоматизации данного процесса.
Идея заключается в разработке и периодическом использовании скрипта, который запускается в моем случае на Linux сервере в центральной точке корпоративной сети. Подразумевается, что скрипт взаимодействует с маршрутизаторами, на которых:
На вход скрипта в качестве параметра поступает файл с ip адресами каналообразующих интерфейсов маршрутизаторов, каналы связи которых мы должны проверить. Количество строк файла не ограничивается каким-либо определенным значением. После последовательного считывания из входного файла соответствующего ip адреса скрипт:
В качестве генератора трафика используется программа TCPBLAST/UDPBLAST, исходные коды которой размещены по ссылке: TCPBLAST/UDPBLAST [1]
Эта программа как нельзя лучше подошла на роль генератора трафика для указанной задачи, т.к. помимо возможности указания в виде параметров командной строки полосы генерируемого трафика она обладает функционалом по запуску генерации трафика с лимитом по времени работы, что позволяет избежать рисков загрузки каналов связи в течение длительного времени в случае возникновения непредвиденных ситуаций, например, когда скрипт аварийно завершит свою работу.
Скрипт получает на входе только ip адрес интерфейса маршрутизатора. Этого вполне достаточно, чтобы определить SNMP индекс интерфейса.
Используемый для этих целей OID: .1.3.6.1.2.1.4.20.1.2
Bandwidth интерфейса и прочие параметры определяются с помощью соответствующих OID с
подстановкой к ним SNMP индекса интерфейса.
#!/usr/bin/perl
use strict;
use warnings;
use POSIX qw(strftime);
use SNMP;
die "Usage: $0 <inputFile>" if ($#ARGV < 0);
my $community = 'community';
### pingLoss function ###
sub pingLoss {
my ($param) = @_;
my @result = `ping $param`;
foreach my $str (@result) {
if ($str =~ /(d+)%/ && $1 < 100) {
return $1;
}
}
return 100;
}
### stressTest function for one host ### sub stressTest {
my $ifIp = shift;
my $ifIndex;
my $ifName = "";
my $ifAlias = "";
my $ifSpeed = "";
my $ifInOctets;
my $ifInOctetsBegin;
my $ifInOctetsEnd;
my $sendBytes;
my $sysName = "";
my $testPeriod;
my $pingLossCount = "";
my $inOutPercent = "";
my $testStatus;
my $nowDateTime = strftime "%Y.%m.%d %H:%M:%S", localtime;
if (&pingLoss("$ifIp -c 3 -i 0.2 -W 2") > 90) {
print "$nowDateTimet$ifIpt$sysNamet$ifNamet$ifAliast$ifSpeedt$inOutPercentt$pingLossCounttping errorn";
return 0;
}
my $sess = new SNMP::Session(DestHost => "$ifIp:161",
Community => $community,
Version => "2c",
NonIncreasing => 1,
UseLongNames => 1,);
$sysName = $sess->get('.1.3.6.1.2.1.1.5.0');
if ($sess->{ErrorNum}) {
print "$nowDateTimet$ifIptt$ifNamet$ifAliast$ifSpeedt$inOutPercentt$pingLossCounttsnmp sysName errorn";
return 0;
}
if ($sysName =~ m/^([w_-]+)./) {
$sysName = $1;
}
$ifIndex = $sess->get('.1.3.6.1.2.1.4.20.1.2.' . $ifIp);
if ($sess->{ErrorNum}) {
print "$nowDateTimet$ifIpt$sysNamet$ifNamet$ifAliast$ifSpeedt$inOutPercentt$pingLossCounttsnmp ifIndex errorn";
return 0;
}
$ifName = $sess->get('.1.3.6.1.2.1.31.1.1.1.1.' . $ifIndex);
if ($sess->{ErrorNum}) {
print "$nowDateTimet$ifIpt$sysNamett$ifAliast$ifSpeedt$inOutPercentt$pingLossCounttsnmp ifName errorn";
return 0;
}
$ifAlias = $sess->get('.1.3.6.1.2.1.31.1.1.1.18.' . $ifIndex);
if ($sess->{ErrorNum}) {
print "$nowDateTimet$ifIpt$sysNamet$ifNamett$ifSpeedt$inOutPercentt$pingLossCounttsnmp ifAlias errorn";
return 0;
}
$ifSpeed = $sess->get('.1.3.6.1.2.1.2.2.1.5.' . $ifIndex);
if ($sess->{ErrorNum}) {
print "$nowDateTimet$ifIpt$sysNamet$ifNamet$ifAliastt$inOutPercentt$pingLossCounttsnmp ifSpeed errorn";
return 0;
}
if ($ifSpeed > 30000000) {
print "$nowDateTimet$ifIpt$sysNamet$ifNamet$ifAliast$ifSpeedt$inOutPercentt$pingLossCounttHigh speed channeln";
return 0;
}
my $sendBytesSec = $ifSpeed * 0.85 / 8;
system("killall udpblast > /dev/null 2> /dev/null");
system("udpblast -c 1000000 --rate $sendBytesSec,100s $ifIp > /dev/null 2> /dev/null &");
sleep(5);
my $testBegin = strftime "%s", localtime;
$ifInOctetsBegin = $sess->get('.1.3.6.1.2.1.2.2.1.10.' . $ifIndex);
if ($sess->{ErrorNum}) {
print "$nowDateTimet$ifIpt$sysNamet$ifNamet$ifAliast$ifSpeedt$inOutPercentt$pingLossCounttsnmp ifInOctetsBegin errorn";
return 0;
}
$pingLossCount = &pingLoss("$ifIp -c 60 -W 1.5");
system("killall udpblast > /dev/null 2> /dev/null");
$ifInOctetsEnd = $sess->get('.1.3.6.1.2.1.2.2.1.10.' . $ifIndex);
if ($sess->{ErrorNum}) {
print "$nowDateTimet$ifIpt$sysNamet$ifNamet$ifAliast$ifSpeedt$inOutPercentt$pingLossCounttsnmp ifInOctetsEnd errorn";
return 0;
}
my $testEnd = strftime "%s", localtime;
$testPeriod = $testEnd - $testBegin;
$ifInOctets = $ifInOctetsEnd - $ifInOctetsBegin;
$sendBytes = $sendBytesSec * $testPeriod * 1.04;
$inOutPercent = sprintf("%d", $ifInOctets * 100 / $sendBytes);
$testStatus = $inOutPercent > 89 && $pingLossCount < 6 ? "Good" : "Bad";
print "$nowDateTimet$ifIpt$sysNamet$ifNamet$ifAliast$ifSpeedt$inOutPercentt$pingLossCountt$testStatusn";
}
### Main ###
open (inputFile, $ARGV[0])
or die "Failed to open $ARGV[0]: $!n";
print "date time tipAddress tsysName tifName tifAlias tifSpeed tinOutPercenttpingLossCountttestStatusn";
foreach my $readString (<inputFile>) {
my $ipAddress = "";
if ($readString =~ m/([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})/ && $1 < 256 && $2 < 256 && $3 < 256 && $4 < 256) {
$ipAddress = "$1.$2.$3.$4";
}
else {last};
&stressTest($ipAddress);
}
Буду очень рад конструктивной критике в целях оптимизации алгоритма скрипта.
Автор: Ковалев Алексей
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/huawei/276679
Ссылки в тексте:
[1] TCPBLAST/UDPBLAST: http://ftp.icm.edu.pl/pub/software/blast/
[2] Источник: https://habrahabr.ru/post/352592/?utm_source=habrahabr&utm_medium=rss&utm_campaign=352592
Нажмите здесь для печати.