Perl/Net :: SNMP:脚本太慢,需要优化

eou*_*uti 1 optimization perl snmp


我想优化我的perl脚本,因为它显示有关网络的信息有点慢.
我不知道可以改变或改进什么来促进脚本执行.
我操纵几个哈希,得到:mac add,index等...我认为它有点沉重,但别无选择.
而且,我做了很多SNMP请求,错误处理可能不是很好.
我复制/粘贴我的脚本及其模块.
提前感谢您阅读我的代码.

它需要args:

  1. 接口名称(例如FastEthernet0/9或FastEthernet0/1 ......)
  2. hostname:交换机的ip
  3. 社区(通常=公共)

希望这是可以理解的.

 #!/usr/bin/perl
    use strict;
    use warnings;
    use Getopt::Long;
    use SnmpUtil;
    use AdresseMac;
    use Net::SNMP;
    use Net::SNMP::Interfaces;

    my $ifname;
    my $hostname;
    my $community;
    my $version = 1;

    GetOptions( "ifname=s"  => \$ifname,
                "host=s"    => \$hostname,
                "community=s"   => \$community,
                "protocol:s"    => \$version);

    my $interfaces = Net::SNMP::Interfaces->new(Hostname => $hostname, Community => $community);
    my $inter = $interfaces->interface($ifname);
    #Get interface $ifname
    my $ifindex = $inter->index();
    #Vitesse
    my $vitesse = $inter->ifHighSpeed();
    #Alias
    my $ifalias = $inter->ifAlias();

    #Seek for VLANs
    my $vlan_trouve;

    #Listing all VLANS
    my $vmVlan = "1.3.6.1.4.1.9.9.68.1.2.2.1.2"; #OID of vlan table
    my $vlans = SnmpUtil->new($hostname, $community);
    my %vl = $vlans->requeteTable($vmVlan);

    $vlans->deconnexion();

    #Get the good VLAN corresponding to index interface
    $vlan_trouve = $vl{$ifindex};

    #Listing : port VLAN <-> @mac
    my $dot1dTpFdbAddress = "1.3.6.1.2.1.17.4.3.1.1";
    my $dot = SnmpUtil->new($hostname, $community."@".$vlan_trouve);
    my %dot1address = $dot->requeteTable($dot1dTpFdbAddress);

    #Listing : numPortBridge <-> port VLAN
    my $dot1dTpFdbPort = "1.3.6.1.2.1.17.4.3.1.2";
    my %portdot = reverse($dot->requeteTable($dot1dTpFdbPort));

    #Listing : num Port bridge <-> ID port switch
    my $dot1dBasePortIfIndex = "1.3.6.1.2.1.17.1.4.1.2";
    my %dotindex = reverse($dot->requeteTable($dot1dBasePortIfIndex));

    #Duplex (auto, half or full)
    my $oid_cisco_duplex = "1.3.6.1.2.1.10.7.2.1.19.".$ifindex;
    my $duplex = $dot->requete($oid_cisco_duplex);
    if ($duplex==1) {
        $duplex= "Auto";
    }
    elsif ($duplex==2) {
        $duplex = "Half";
    }
    elsif ($duplex==3) {
        $duplex= "Full";
    }
    #Close connection
    $dot->deconnexion();

    #Go back up, to find mac add
    my $numportbridge = $dotindex{$ifindex};
    if (!defined($numportbridge)) {
        print "Erreur : $ifindex not found in list : num Port bridge <-> ID port switch\n";
        exit 2;
    }
    my $portVlan = $portdot{$numportbridge};
    if (!defined($portVlan)) {
        print "Erreur : $numportbridge not found in list : numPortBridge <-> ports du VLAN\n";
        exit 3;
    }
    my $add = uc($dot1address{$portVlan});
    if (!defined($add)) {
        print "Erreur : $portVlan not found in list : ports du VLAN <-> \@mac\n";
        exit 4;
    }
    $add =~ s/^0X//g;
    printf "<b>Port : $ifname</b><br/>Index $ifindex on VLAN : $vlan_trouve<br/>\@mac : $add<br/>Speed=$vitesse Mbps Alias=$ifalias<br/>Duplex: $duplex\n";
Run Code Online (Sandbox Code Playgroud)

这是SnmpUtil.pm:

#!/usr/bin/perl
use strict;
use warnings;
use Net::SNMP;
package SnmpUtil;

our ($session, $error);

sub new {
  my ($classe, $hostname, $community) = @_;
  my $this = {
    "hostname"  => $hostname,
    "community" => $community
  };
  bless($this, $classe);
  $this->{connexion} = $this->connexion;
  return $this;
}

sub connexion {
    my ($this) = @_;

    ($session, $error) = Net::SNMP->session(
        -hostname  => $this->{hostname},
        -community => $this->{community},
        -version   => "1",
        -timeout   => 3,
    );
    request_error_connexion() if (!defined($session));
}

sub request_error_connexion {   
    my ($this) = @_;
    print "Erreur : can't connect to host\n";
    print "Erreur : $error\n";
    if ($error =~ /The argument "-community" is unknown/)
        {
                # protocol SNMP version 3 not working 
                exit 3;  # code ret final = 3*256 = 768
        }
    else
    {
        exit 1; # code retour final = 1*256 = 256
    }
}

sub request_error {
        my ($this) = @_;
        print "Error : no answer from host\n";
        printf "Erreur : %s\n",$session->error;
        if ($session->error =~ /No response from remote host/)
        {
                #host ok, bad community or host refuse connection
                $session->close;
                exit 2; # code retour final = 2*256 = 512
        }
        else
        {
                #can not find table
                $session->close;
                exit 4; # code retour final = 4*256 = 1024
        }
}

sub requeteTable {
    my ($this, $oid) = @_;
    my $result = $session->get_table( -baseoid => $oid );
    request_error() if (!defined($result));
    my %tab = ();

    foreach my $i (Net::SNMP::oid_lex_sort(keys %{$result})) {
        my $index = $i;
        $index =~ s/$oid.//;
        $tab{ $index } = $result->{$i};  
        #print $index."--".$result->{$i}."\n";
    }

    return %tab;
}

sub requete {
    my ($this, $oid) = @_;
    my $result = $session->get_request($oid);
    request_error() if (!defined($result));
    return $result->{$oid}; 
}

sub deconnexion {
    my ($this) = @_;
    $session->close();
}

1;
Run Code Online (Sandbox Code Playgroud)

AdresseMac.pm模块没用,它只是将dec转换为十六进制,反之亦然.

感谢您的帮助,
为找到优化的人带来巨大回报;​​)

PS:忘了说,我在cisco开关2960上工作.

Wes*_*ker 6

您可能不喜欢这个答案,但是Net-SNMP支持使用C-bindings而不是Net :: SNMP中的all-in-perl模块实现编写的perl模块(仅称为SNMP)的原因之一就是C结合速度明显加快.Giovanni Marzot编写了Net-SNMP C绑定绑定的初始实现,测得C/perl绑定实现的速度比all-perl版本快10倍.如果您开始进入经过身份验证/加密的SNMPv3,那么它会变得更快.但是,我不知道这是否是你问题的根源.只是一个数据点.perl profiler真的会让你知道.

另一点需要考虑:如果您要查询大量主机,请考虑构建代码,以便您可以使用异步请求一次发送多个查询,并使用SNMPv2c同时使用GetBulk请求.这两个优化也将大大提高速度.

更新了每个请求的链接:

请注意,Net-SNMP有一个您可能感兴趣的gettable()函数,它可以进行大量优化.