Perl / Net :: SNMP: script demasiado lento, necesita optimizar


Me gustaría optimizar mi script de Perl porque es un poco lento para mostrar información sobre la red.
No sé qué se puede cambiar o mejorar para impulsar la ejecución del script.
Manipulo varios hashes, para obtener: mac add, index, etc ... Creo que es un poco pesado, pero no hay otra opción.
Además, hago muchas solicitudes SNMP y el manejo de errores tal vez no sea excelente.
Copio / pego mi script y su módulo.
Gracias de antemano por leer mi código.

Toma argumentos:

  1. nombre de la interfaz (ej. FastEthernet0 / 9 o FastEthernet0 / 1 ...)
  2. nombre de host: ip del conmutador
  3. comunidad (a menudo = público)

Espero que esto sea comprensible.

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

Aquí está 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;

El módulo AdresseMac.pm es inútil, es solo para convertir dec a hexadecimal y viceversa.

Gracias por tu ayuda,
gran recompensa para quien encuentra la optimización;)

PD: olvidé decir, trabajo en el conmutador cisco 2960.

preguntado el 10 de mayo de 11 a las 12:05

1 Respuestas

Puede que no le guste esta respuesta, pero una de las razones por las que Net-SNMP admite un módulo perl (llamado simplemente SNMP) escrito utilizando enlaces C en lugar de la implementación del módulo todo en perl realizada en Red :: SNMP es que las fijaciones C son significativamente más rápidas. Giovanni Marzot, quien escribió la implementación inicial del enlace de enlace C de Net-SNMP, midió que la implementación de enlace de C / perl era hasta 10 veces más rápida que la versión de todo perl. Y si comienza a ingresar al SNMPv3 autenticado / encriptado, entonces se vuelve aún más rápido. Yo no sabes qué sin embargo, si esta es la fuente de sus problemas. Solo un punto de datos. Un generador de perfiles de Perl realmente te lo haría saber.

Otro punto a considerar: si está consultando muchos hosts, piense en la arquitectura de su código para que pueda enviar múltiples consultas a la vez usando solicitudes asincrónicas y usando solicitudes GetBulk usando SNMPv2c también. Estas dos optimizaciones también aumentarán enormemente la velocidad.

Actualizado con enlaces por solicitud:

Tenga en cuenta que Net-SNMP tiene una función gettable () que puede interesarle y que realiza muchas optimizaciones.

Respondido 08 Abr '14, 16:04

Ok, gracias por tu publicación, solo uso SNMP v1, no quieren usar una versión más nueva de SNMP. ¿Tiene algunos enlaces para usar la biblioteca SNMP más rápida con Perl? - eouti

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.