0

以下のスクリプトを一緒にハックして、テストサーバーへのトラップを生成できるようにしました。私が本当に必要としているのは、大規模なトラップを生成して、受信側のツールをチェックして、UDP、Net :: SNMP、Perlなどのボトルネックがどこにあるかを見つけることができるものです。

このスクリプトで1秒あたり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);
    }
}
4

1 に答える 1

0

おそらくParallel::ForkManagerのようなものを使用しますか? さらに、SNMP コレクタのスケーラビリティのテストに関しては、単一のホストがトラップを高速で送信するだけでなく、多くのホストからトラップを受信するユース ケースに関心があるでしょう。そのためには、pssh の使用を検討することをお勧めします。

問題の 1 つは、pure-perl での Net::SNMP の遅さかもしれません。おそらく、シェル経由で snmptest や snmptrap を実行した方が速いのではないでしょうか? 試すだけの価値があります。

于 2013-01-27T02:58:09.880 に答える