The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

SNMP::Multi - Perform SNMP operations on multiple hosts simultaneously

SYNOPSIS

    use SNMP::Multi;

    my $req = SNMP::Multi::VarReq->new (
        nonrepeaters => 1,
        hosts => [ qw/ router1.my.com router2.my.com / ],
        vars  => [ [ 'sysUpTime' ], [ 'ifInOctets' ], [ 'ifOutOctets' ] ],
    );
    die "VarReq: $SNMP::Multi::VarReq::error\n" unless $req;

    my $sm = SNMP::Multi->new (
        Method      => 'bulkwalk',
        MaxSessions => 32,
        PduPacking  => 16,
        Community   => 'public',
        Version     => '2c',
        Timeout     => 5,
        Retries     => 3,
        UseNumeric  => 1,
        # Any additional options for SNMP::Session::new() ...
    )
    or die "$SNMP::Multi::error\n";

    $sm->request($req) or die $sm->error;
    my $resp = $sm->execute() or die "Execute: $SNMP::Multi::error\n";

    print "Got response for ", (join ' ', $resp->hostnames()), "\n";
    for my $host ($resp->hosts()) {

        print "Results for $host: \n";
        for my $result ($host->results()) {
            if ($result->error()) {
                print "Error with $host: ", $result->error(), "\n";
                next;
            }

            print "Values for $host: ", (join ' ', $result->values());
            for my $varlist ($result->varlists()) {
                print map { "\t" . $_->fmt() . "\n" } @$varlist;
            }
            print "\n";
        }
    }

DESCRIPTION

The SNMP::Multi package provides a mechanism to perform SNMP operations on several hosts simultaneously. SNMP::Multi builds on G. Marzot's SNMP Perl interface to the UC-Davis SNMP libraries, using asynchronous SNMP operations to send queries/sets to multiple hosts simultaneously.

Results from all hosts are compiled into a single object, which offers methods to access the data in aggregate, or broken down by host or the individual request.

SNMP::Multi supports SNMP GET, SET, GETNEXT, GETBULK and BULKWALK requests. It also performs PDU packing in order to improve network efficiency, when packing is possible.

OPTIONS

The SNMP::Multi constructor takes the following options to control its behavior. Any other options are stored and handed to the SNMP::Session constructor when a new SNMP session is created. As the behavior of SNMP::Multi depends upon certain SNMP::Session parameters (i.e. Timeout), these will be listed below as SNMP::Multi options. These "overlapped" options will be passed un-changed to SNMP::Session's constructor.

``Method''

    Specify one of get, set, getnext, getbulk or bulkwalk. The appropriate SNMP request will be made to each host for each set of variables requested by the user.

    This parameter is required. There is no default value.

``Requests''

    The SNMP::Multi object may be given a new set of requests via the request() method, or by passing a reference to an SNMP::Multi::VarReq object into the constructor. Any VarReq requests given to the SNMP::Multi object through the constructor will be overwritten by subsequent calls to SNMP::Multi::request().

    This parameter is optional.

``PduPacking''

    The maximum number of variable requests that will be packed into a single SNMP request is controlled by the ``PduPacking'' parameter. PDU packing improves the efficiency and accuracy of SNMP requests by reducing the number of packets exchanged. Setting this variable to '0' will disable PDU packing altogether. PDU packing is not performed for SNMP GETBULK or BULKWALK requests.

    This optional parameter defaults to the value of $SNMP::Multi::pdupacking.

``MaxSessions''

    This variable controls the maximum number of SNMP sessions that will be kept open simultaneously. Setting ``MaxSessions'' higher increases the number of agents being queried at any time, up to the maximum limit of file descriptors available to the process. SNMP::Multi detects "out of resources" conditions (i.e. EMFILE) and adjusts the number of open connections accordingly.

    This optional parameter defaults to the value of $SNMP::Multi::maxsessions.

``Concurrent''

    The value of ``Concurrent'' limits the number of requests that may be "in flight" at any time. It defaults to the value of ``MaxSessions'' (see above). Setting this value higher may reduce the overall runtime of the SNMP::Multi request, but will also likely increase network traffic and congestion (current maintainer has had SNMP::Multi running smoothly with concurrent set to 512).

    This optional parameter defaults to the value of $SNMP::Multi::maxsessions or the object's 'MaxSessions' parameter.

``GetbulkMax''

    Sets the default "maxrepetitions" value for SNMP GETBULK and BULKWALK requests. This value may be overridden on a per-request basis (by specifying the 'maxrepetitions' parameter in the SNMP::Multi::VarReq constructor).

    This optional parameter defaults to the value of $SNMP::Multi::getbulkmax.

``ExternalSelect''

    If ``ExternalSelect'' is specified, the SNMP::Multi's execute() method will return immediately after dispatching the first volley of SNMP requests. The caller can then use SNMP::select_info() to get a list of the current file descriptors for the SNMP sessions, and select() on them. When one of the fd's becomes readable, it should be handed to SNMP::reply_cb() to handle it.

    Note that SNMP bulkwalks use the callbacks to dispatch continuing GETBULK requests. This causes the file descriptor to be readable, but SNMP::reply_cb() calls an internal callback in SNMP.xs's bulkwalk implementation, not the SNMP::Multi handler callback. When the walk completes, the SNMP::Multi callback will be called with the specified arguments.

``Retries'' (shared with SNMP::Session)

    The ``Retries'' options specifies the maximum number of retries for each SNMP request. Note that this is the number of retries, not the total number of attempted requests.

    This optional parameter defaults to the value of $SNMP::Multi::maxretries.

``Timeout'' (shared with SNMP::Session)

    The ``Timeout'' parameter specifies the timeout in seconds between successive retries for SNMP requests. The overall runtime for the complete SNMP::Multi request will be approximately :

            (retries + 1) * timeout

    Please note that this is the lower-bound on the time-out. Without sufficient resources (especially file descriptors) to optimize the network communications, completing all requested SNMP operations can take considerably longer.

    An over-all timeout may be specified as the optional "timeout" parameter to the SNMP::Multi's execute() method.

    This optional parameter defaults to the value of $SNMP::Multi::timeout.

``Community'' (shared with SNMP::Session)

    The ``Community'' parameter specifies the SNMP community string to use when making requests from SNMP agents. No mechanism exists at this time to specify a different community for individual agents.

    This optional parameter defaults to the value of $SNMP::Multi::community.

``Version'' (shared with SNMP::Session)

    The ``Version'' option specifies the SNMP protocol to use with the agents. Due to the poor error reporting in SNMP v1, it is recommended that SNMP v2c or v3 be used to communicate with the agents when possible.

    This optional parameter defaults to the value of $SNMP::Multi::snmpversion.

METHODS

The SNMP::Multi object provides several methods for the caller. In most cases, only the new(), request(), and execute() methods need to be used. The various methods are documented in approximately the order in which they are normally called.

SNMP::Multi::new(...)

    Create a new instance of an SNMP::Multi object. See above for a description of the available constructor options.

SNMP::Multi::request( <ref to SNMP::Multi::VarReq> )

    request() arranges for the set of host/variable requests stored in the SNMP::Multi::VarReq object to be transferred to the SNMP::Multi object. This can also be done in the constructor using the ``requests'' option.

    Note that the request() method is not cumulative -- previous requests will be overwritten by subsequent calls to request().

    SNMP::Multi::execute( [timeout] )

      The execute() function performs the actual work in SNMP::Multi, returning when all requests have been answered or timed out. An optional `timeout' argument to execute() specifies an overall timeout, regardless of the number and timing of retries.

      execute() returns a reference to an SNMP::Multi::Response object. This object provides methods to conveniently access the returned data values.

    SNMP::Multi::error()

      If an error occurs while SNMP::Multi is executing, the caller may retrieve a descriptive string describing the error from the error() method.

    SNMP::Multi::remaining( $req )

      The remaining() method produces an SNMP::Multi::VarReq that is populated with the requests for any un-answered or un-sent request hunks. This VarReq may then be passed to another SNMP::Multi object (or the same one). This allows an application to loop on timeouts like this:

          my $req = SNMP::Multi::VarReq->new( ... );
          my $sm  = SNMP::Multi->new( ... );
          while ($req) {
              $sm->request($req);
              my $resp = $sm->execute();
              handle_response($resp);
      
              print "Timeout - retrying" if ($req = $sm->remaining());
          }

      You can accumulate remaining requests by passing an already existing SNMP::Multi::VarReq object as an argument. Remaining requests will then be added to that object. That allows us to to collect all remaining ones with ease, while looping over huge number of hosts.

Building SNMP::Multi::VarReq Requests

SNMP variable requests are composed and passed to the SNMP::Multi object through an auxiliary class called an SNMP::Multi::VarReq. This class simply collects SNMP requests for variables and hosts (and optionally validates them).

The interface to SNMP::Multi::VarReq is very simple, providing only new() and add() methods. They take the following arguments:

    'vars'           => [ list of Varbinds to be requested (REQUIRED) ]
    'hosts'          => [ list of hosts for this variable list ]
    'nonrepeaters'   => [ GETBULK/BULKWALK "nonrepeaters" parameter ]
    'maxrepetitions' => [ GETBULK/BULKWALK "maxrepetitions" parameter ]

Every call to new() or add() must contain a list of SNMP variables. If the hosts parameter is not specified, the variable list will be requested from all hosts currently known by the SNMP::Multi::VarReq object. If a host list is given, the variables will be requested only from the named hosts.

Some simple sanity checks can be performed on the VarReq by calling its validate() method, or by setting $SNMP::Multi::VarReq::autovalidate to 1 before calling the new() method.

An example of building up a complicated request using new() and add():

    Start with:

        $r = SNMP::Multi::VarReq->new(
            hosts => [ qw/ A B C / ],
            vars  => [ qw/ 1 2 3 / ]
        );

    to get:

        A: 1 2 3
        B: 1 2 3
        C: 1 2 3

    Now add a var to each host:

        $r->add( vars => [ qw/ 4 / ] );

    to get:

        A: 1 2 3 4
        B: 1 2 3 4
        C: 1 2 3 4

    Add a var to a specific set of hosts:

        $r->add( hosts => [ qw/ A C / ],
                 vars  => [ qw/ 5   / ] );

    to get:

        A: 1 2 3 4 5
        B: 1 2 3 4
        C: 1 2 3 4 5

    Finally, create two new hosts and add a pair of vars to them:

        $r->add( hosts => [ qw/ D E / ],
                 vars =>  [ qw/ 6 7 / ] );

    to get:

        A: 1 2 3 4 5
        B: 1 2 3 4
        C: 1 2 3 4 5
        D: 6 7
        E: 6 7

The SNMP::Multi::VarReq object also provides a dump() method which generates a simple dump of the current host/var requests.

SNMP PDU Packing Features

SNMP::Multi packs SNMP::Varbind requests into larger request "hunks" to reduce the number of request/response pairs required to complete the SNMP::Multi request. This packing is controlled by the SNMP::Multi 'PduPacking' parameter.

For instance, assume your application creates an SNMP::Multi object with a 'PduPacking' value of 3. SNMP::Multi will pack 5 single SNMP variable requests into two distinct requests. The first request will contain the first 3 variables, the second will get the remaining two variables.

PDU packing is not done for SNMP GETBULK and BULKWALK requests. The feature may be disabled by setting the 'PduPacking' parameter to '0'.

Accessing SNMP Data From Agent Responses

The SNMP::Multi::execute() method returns the responses from the SNMP agents in an SNMP::Multi::Response object. This object, indexed by hostname, consists of per-host response objects (SNMP::Multi::Response::Host's), each of which contains a list of SNMP::Multi::Result objects. The Result objects connect an SNMP::VarList with the error status (if any) from the SNMP request. An entry is only made in the Response object if the SNMP agent returned some response to SNMP::Multi.

This is fairly complicated, but the various objects provide accessor methods to make access to the SNMP responses simple. Assume your application is structured something like this example source code:

    my $req = SNMP::Multi::VarReq->new( hosts => [...],
                                        vars  => [...] );
    my $sm  = SNMP::Multi->new( ... requests => $req, ... );
    my $response = $sm->execute( $overall_timeout );
    die $sm->error() if $sm->error();

Now the data can be accessed through methods on the objects that make up the SNMP::Multi::Response returned by execute(). An SNMP::VarList object is returned for each variable requested. This normalizes the return format across all SNMP operations (including bulkwalks).

See the SYNOPSIS section above for an example of how to access the SNMP data values after calling the execute() method.

SNMP::Multi::Response methods
hostnames()

    Return a list of the hosts that responded to the SNMP queries made by execute().

values()

    Return all values returned by the SNMP agents, collated into a single list. This method can be used when the application is not concerned with which value was returned by a specific host (i.e. summing up octet counts on router interfaces).

hosts()

    Returns a list of SNMP::Multi::Response::Host objects, one per host queried by the SNMP::Multi::execute() method.

SNMP::Multi::Response::Host methods
hostname()

    Return the hostname associated with this set of responses. The reference may also be stringified to get the hostname :

            print "This is the list of results for $host: \n";
values()

    Return all values received in response to requests made to the associated host.

results()

    Returns a list of SNMP::Multi::Result objects for this host. There is one Result object for each request sent to the SNMP agent on this host.

SNMP::Multi::Result methods

The SNMP::Multi::Result object correlates SNMP error information with the response to an SNMP request.

error()

    Return a printable string describing the error encountered for this variable, or undef if no error occurred.

values()

    Return a list of the values received for this request.

varlists()

    Return an array of SNMP::VarList objects, one per variable requested in the SNMP packet. This format is consistent for all SNMP operations, and is required to support bulkwalks (in which the number of returned values per variable is not known a priori to the calling application).

EXAMPLES

A complete example is given in the "SYNOPSIS" section above.

CAVEATS

The VarList returned for GETBULK requests is "decoded" by SNMP::Multi into an array of single VarLists, one for each requested variable. This behavior differs from the return from the getbulk() method in the SNMP.pm module, but is consistent with the return value of SNMP.pm's bulkwalk() method.

Note that the V1 SNMP protocol has very limited error reporting (the agent returns no values, and the 'errind' is set to the index of the offending SNMP variable request). The SNMP::Multi module adjusts the 'errind' index to indicate which of the variables request requested for a host have failed, regardless of the number of actual packets exchanged. This is necessary to support SNMP::Multi's transparent pdu-packing feature.

SNMP::Multi relies on features added to the SNMP module by Electric Lightwave, Inc. These features have been incorporated into UCD-SNMP releases 4.2 and later. You must have SNMP 4.2 or later installed to use this package.

Using SNMP::Multi with large numbers of hosts or large requests may cause network congestion. All targets may send PDU's to the originating host simultaneously, which could cause heavy traffic and/or dropped packets at the host. Adjusting the Concurrent and PduPacking variables can mitigate this problem.

Network congestion may be a serious problem for bulkwalks, due to multiple packets being exchanged per session. However, network latency and variable target response times cause packets in multiple bulkwalk exchanges to become spread out as the walk progresses. The initial exchange, however, will always cause congestion.

BUGS

There is no interface to specify a different SNMP community string for a specific host, although the community is stored on a per-host basis.

SEE ALSO

SNMP, the NetSNMP homepage at http://www.net-snmp.org/.

AUTHOR

Karl ("Terminator rAT") Schilke <rat@eli.net>

CONTRIBUTORS

Joshua Keroes, Todd Caine, Toni Prug <tony@irational.org>

COPYRIGHT

Developed by Karl "Terminator rAT" Schilke for Electric Lightwave, Inc. Copyright (c) 2000-2002 Electric Lightwave, Inc. All rights reserved.

Co-maintained by Toni Prug.

This software is provided ``as is'' and without any express or implied warranties, including, without limitation, the implied warranties of merchantibility and/or fitness for a particular purpose.

This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself.

8 POD Errors

The following errors were encountered while parsing the POD:

Around line 93:

'=item' outside of any '=over'

Around line 250:

You forgot a '=back' before '=head1'

Around line 257:

'=item' outside of any '=over'

Around line 268:

You can't have =items (as at line 277) unless the first thing after the =over is an =item

Around line 326:

You forgot a '=back' before '=head1'

You forgot a '=back' before '=head1'

Around line 444:

'=item' outside of any '=over'

Around line 480:

'=item' outside of any '=over'

Around line 551:

You forgot a '=back' before '=head1'