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

时间:2011-05-10 12:57:10

标签: perl optimization snmp


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

它包含args:

  1. 接口名称(例如FastEthernet0 / 9或FastEthernet0 / 1 ......)
  2. 主机名:交换机的IP
  3. 社区(通常=公开)
  4. 希望这是可以理解的。

     #!/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";
    

    这是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;
    

    AdresseMac.pm模块没用,只是将dec转换为hex&amp; amp;反之亦然。

    感谢您的帮助,
    找到优化者的巨大回报;​​)

    PS:忘了说,我在cisco switch 2960上工作。

1 个答案:

答案 0 :(得分:6)

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

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

已更新,每个请求都包含链接:

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