用于规模测试的Perl SNMP陷阱生成器?

时间:2013-01-26 20:46:11

标签: perl snmp

我一起攻击了下面的脚本,让我为测试服务器生成陷阱。我真正需要的是能够大规模生成陷阱的东西,以便我可以在接收端检查我的工具以找出瓶颈所在的位置,例如UDP,Net :: SNMP,Perl等。

我曾希望这个剧本会让我产生类似10k事件/秒的东西,但我很遗憾地错了。

有没有人知道我是否可以在Perl中执行此操作或建议使用其他方法来执行此操作?

#! /usr/bin/perl

use strict;
use warnings;
use Log::Fast;
use FindBin;
use Getopt::Long;
use File::Basename;
use Cwd qw(abs_path);
my $ROOT_DIR = abs_path("$FindBin::Bin/..");
use POSIX qw/strftime/;
use Net::SNMP qw(:ALL); 
use Time::HiRes qw( time sleep );

#FIXME - I had to add below for Perl 5.10 users.
# on Perl 5.10, I would get the following when running:
# perl -e"autoflush STDOUT, 1;"
# Can't locate object method "autoflush" via package "IO::Handle" at -e line 1.
use FileHandle;

# Create default logger, will reconfigure it as soon as we read configuration from database
my $log = Log::Fast->global();

my $myname = $0;
$myname =~ s{.*/}{};    # leave just program name without path

# Command line options
my $options = {
    debug    => 0,
    verbose  => 0,
    logfile => "./$myname.log",    
    help        => 0,
    community        => "public",
    trapsource        => "127.0.0.1",
    timelimit        => 1,
};

sub usage_and_exit {
    my ($exit_code) = @_;
    print STDERR qq{
    This program is used to generate SNMP traps to a specified host at a specified rate
    Usage: $myname [-o --option] 
    -h        : this (help) message
    -d        : debug level (0-5) (0 = disabled [default])
    -v        : Also print results to STDERR
    -l        : log file (defaults to local dir
    -r        : Rate (events/sec)
    -ts       : host to generate messages FROM
    -td       : host to generate messages TO
    -tl       : Run for this many seconds (default 1)
    -c        : community
    Example: $myname  -td 192.168.28.29 -r 1 -tl 5 -v
    };
    exit($exit_code);
}

GetOptions(
    'debug|d=i'       => \$options->{debug},
    'help|h!'         => \$options->{help},
    'verbose|v!'      => \$options->{verbose},
    'logfile|l=s'    => \$options->{logfile},
    'rate|r=i' => \$options->{rate},
    'trapsource|ts=s'     => \$options->{trapsource},
    'trapdest|td=s'     => \$options->{trapdest},
    'community|c=s'     => \$options->{community},
    'timelimit|tl=i' => \$options->{timelimit},
) or usage_and_exit(1);    # got some invalid options

if ( $options->{help} ) {
    usage_and_exit(0);
}

# Reconfigure log to use logfile (as we finally got it from $settings), also
# set proper level and output based on $options{verbose} and $options{debug}
setup_log();

# Finally we are initialized, announce this to the world :-)
$log->INFO("Program initialized successfully");

my $date = strftime "%Y-%m-%d %H:%M:%S", localtime;

# start func
my $period = 1 / $options->{rate};
my $start = time();
my $limit = time() + $options->{timelimit};
my $total = $options->{rate} * $options->{timelimit};
$log->INFO("Generating $options->{rate} trap(s) every second for $options->{timelimit} seconds (1 every $period seconds, $total total events)");
while($start < $limit) {
    my $elapsed = time() - $start;
    if ($elapsed < $period) { 
        sleep($period - $elapsed);
        my ($session, $error) = Net::SNMP->session(
            -hostname  => $options->{trapdest},
            -community => $options->{community},
            -port      => SNMP_TRAP_PORT,      # Need to use port 162
            -version   => 'snmpv2c'
        );
        if (!defined($session)) {
            $log->INFO("ERROR: %s.", $error);
            exit 1;
        }
        my $result = $session->snmpv2_trap(
            -varbindlist => [
            '1.3.6.1.2.1.1.3.0', TIMETICKS, 600,
            '1.3.6.1.6.3.1.1.4.1.0', OBJECT_IDENTIFIER, '1.3.6.1.4.1.326',
            '1.3.6.1.6.3.18.1.3.0', IPADDRESS, $options->{trapsource}
            ]
        );
        if (!defined($result)) {
            $log->INFO("ERROR: %s.", $session->error());
        } else {
            $log->INFO("SNMPv2-Trap-PDU sent from $options->{trapsource} to $options->{trapdest}.");
        }
    } else {
        $start = time();
    }
}

#-------------------------------------------
# There should only be subs from here down
#-------------------------------------------

# =================================================================================================
# Helper functions
# =================================================================================================

# commify not used yet
sub commify {
    my $text = reverse $_[0];
    $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
    return scalar reverse $text;
}

sub setup_log {
    my $log_dir = dirname($options->{logfile});

    # Create log dir, and build log path if not provided by command line option
    if ( !-d $log_dir ) {
        mkdir( $log_dir, 0755 ) or die("mkdir $log_dir: $!");
    }
    if ( !$options->{logfile} ) {
        $options->{logfile} = $log_dir . "/" . basename( $0, '.pl' ) . '.log';
    }

    my $log_options = {};

    # Set up output to file or both file and stderr
    if ( $options->{verbose} ) {

        # make multiplexer FH sending data both to file and STDERR
        open( my $fh, '>>:tee', $options->{logfile}, \*STDERR )
            or die("$options->{logfile}: $!");
        $fh->autoflush(1);
        $log_options->{fh} = $fh;
    }
    else {
        open( my $fh, '>>', $options->{logfile} ) or die("$options->{logfile}: $!");
        $log_options->{fh} = $fh;
    }

    # Setup extra information to put in every log line, depending on debug level
    if ( $options->{debug} > 1 ) {
        $log_options->{prefix} = "%D %T %S [%L] ";
    }
    else {
        $log_options->{prefix} = "%D %T [%L] ";
    }

    $log_options->{level} = $options->{debug} > 0 ? 'DEBUG' : 'INFO';

    $log->config($log_options);

    $SIG{__WARN__} = sub {
        my $msg = shift;
        $msg =~ s/\n//;
        $log->WARN($msg);
    };

    $log->INFO("Starting logging to $options->{logfile} with pid $$");
}

sub DEBUG {
    my ( $level, @log_args ) = @_;
    if ( $options->{debug} >= $level ) {
        $log->DEBUG(@log_args);
    }
}

1 个答案:

答案 0 :(得分:0)

也许使用Parallel::ForkManager之类的东西?此外,特别考虑测试SNMP收集器的可扩展性,您可能会对从许多HOSTS接收陷阱的用例感兴趣,而不仅仅是单个主机以高速率发送陷阱。为此,您可能希望使用pssh。

一个问题可能是纯perl中Net :: SNMP的缓慢 - 可能通过shell执行snmptest或snmptrap可能会更快?值得一试。