Section 11.8. Pinging with Cisco


11.8. Pinging with Cisco

Using ICMP messages (also know as "pinging") to determine if a host is up is a common and simple network monitoring technique. Pinging a small number of hosts is not that challenging. But if you have many hosts that are distributed all over the place, things could get ugly.

If the polling interval used is short enough, you could run into the problem where the nth poll hasn't finished before the nth+1 poll begins. Another problem could be that the machine you want to ping from doesn't have proper routing to the host or hosts you want to monitor.

Cisco routers and some switches support the Cisco ping MIB (download from ftp://ftp.cisco.com/pub/mibs/v2/CISCO-PING-MIB.my). Basically, this feature allows you to have routers perform ICMP operations on your behalf. In effect, you can have a distributed ping system.

In this script,[*] we'll use SNMP to configure a Cisco router to perform pings on our behalf:

[*] Note that this Perl script uses the SNMP Perl API based on Net-SNMP. See Appendix E for an introduction to this Perl module.

     #!/usr/bin/perl     use SNMP;     #     # This script was adapted from the one that comes with Net-SNMP     #     my %ipsToPing = (           "192.168.0.48" => 333,     );     my $router = "192.168.0.130";     my $community = "public";     my $version = 1;     my $sess = new SNMP::Session (DestHost => $router,               Community => $community,               Retries => 1,               Version => $version);     my $ciscoPingEntry = ".1.3.6.1.4.1.9.9.16.1.1.1";     my $ciscoPingEntryStatus = "$ciscoPingEntry.16";     my $ciscoPingEntryOwner = "$ciscoPingEntry.15";     my $ciscoPingProtocol = "$ciscoPingEntry.2";     my $ciscoPingPacketCount = "$ciscoPingEntry.4";     my $ciscoPingPacketSize = "$ciscoPingEntry.5";     my $ciscoPingAddress = "$ciscoPingEntry.3";     my $ciscoPingSentPackets = "$ciscoPingEntry.9";     my $ciscoPingReceivedPackets = "$ciscoPingEntry.10";     my $ciscoPingMinRtt = "$ciscoPingEntry.11";     my $ciscoPingAvgRtt = "$ciscoPingEntry.12";     my $ciscoPingMaxRtt = "$ciscoPingEntry.13";     my $ciscoPingCompleted = "$ciscoPingEntry.14";     #     # Set up Cisco Ping table with targets we want to ping     #     foreach my $target (sort keys %ipsToPing){         my $row = $ipsToPing{$target};         # We must encode the IP we want to ping to HEX         my $dec = pack("C*",split /\./, $target);         $sess->set([             # First we clear the entry for this target             [$ciscoPingEntryStatus, $row, 6, "INTEGER"],             # Now we create a new entry for this target             [$ciscoPingEntryStatus, $row, 5, "INTEGER"],             # Set the owner of this entry             [$ciscoPingEntryOwner, $row, "kjs", "OCTETSTR"],             # Set the protocol to use, in this case "1" is IP             [$ciscoPingProtocol, $row, 1, "INTEGER"],             # Set the number of packets to send             [$ciscoPingPacketCount, $row, 20, "INTEGER"],             # Set the packet size             [$ciscoPingPacketSize, $row, 150, "INTEGER"],             # Finally set the target we want to ping             [$ciscoPingAddress, $row, $dec, "OCTETSTR"]]);         # This enables this target and causes the router to start pinging         $sess->set([[$ciscoPingEntryStatus, $row, 1, "INTEGER"]]);         if($sess->{ErrorStr}){            print "An Error Occurred: $sess->{ErrorStr}\n";            exit;         }     }     # Give router time to do its thing...     sleep 30;     #     # Get results     #     foreach my $target (sort keys %ipsToPing){        my $row = $ipsToPing{$target};        my ($sent, $received, $low, $avg, $high, $completed) = $sess->get([           [$ciscoPingSentPackets, $row], [$ciscoPingReceivedPackets, $row],           [$ciscoPingMinRtt, $row], [$ciscoPingAvgRtt, $row],           [$ciscoPingMaxRtt, $row], [$ciscoPingCompleted, $row]]);        printf "($target)Packet loss: %d% (%d/%d)\n", (100 * ($sent-$received)) /        $sent,             $received, $sent;        print "Average delay $avg (low: $low high: $high)\n";        # Here we remove this target's entry from the Cisco Ping Table        $sess->set([$ciscoPingEntryStatus, $row, 6, "INTEGER"]);      } 

Let's look at some details of this script:

  • The ipsToPing hash is used to map all the target hosts we want our Cisco router to ping for us. Note that we are mapping the IP address to a number. This number uniquely identifies this IP address. If you want to add other IP addresses, make sure they all have unique numbers. This is because the Cisco ping MIB maintains a table of the hosts it has to ping and each entry in the table needs a unique number.

  • Look at the first foreach( ) loop where we go through the ipsToPing hash. This is where we create new entries on the Cisco router. The first item we set is the ciscoPingEntryStatus. It is defined in the Cisco ping MIB as follows:

         ciscoPingEntryStatus OBJECT-TYPE             SYNTAX     RowStatus             MAX-ACCESS read-create             STATUS     current             DESCRIPTION                     "The status of this table entry.  Once the entry status is                     set to active, the associate entry cannot be modified until                     the sequence completes (ciscoPingCompleted is true)."             ::= { ciscoPingEntry 16 } 

    Its SYNTAX is RowStatus. RowStatus is a textual convention in the SNMPv2 textual conventions MIB. Basically, RowStatus is used to control the creation and deletion of table entries and can take the values listed in Table 11-1.

    Table 11-1. RowStatus values

    Value

    Status

    1

    active

    2

    notInService

    3

    notReady

    4

    createAndGo

    5

    createAndWait

    6

    destroy


    The first line of the SNMP set is issued against the ciscoPingEntryStatus OID with a value of 6, which is destroy. This removes a previously defined entry in this table for the row representing this target IP. The next line also issues a set against ciscoPingEntryStatus, but this time we create a new entry for the target IP address by using a value of 5. This creates the entry but places the row in a holding pattern. The router will not perform any action until we tell it to. The other parameters to the multipart set are self-explanatory. The action we take, before we leave the loop, is to enable the table entry by setting ciscoPingEntryStatus to 1, which is active. This will cause the Cisco router to begin its ping of the target.

  • Once out of the loop, the script pauses for a bit to let the router do its thing. The final foreach( ) loop gathers the statistics that the router has captured for the target we previously configured it to ping. The final set operation in the loop removes this target's entry from the table. It does so by setting ciscoPingEntryStatus to 6, which destroys the row from the table.

Here's sample output from a run of this script:

     $ ./pingmib.pl     (192.168.0.48)Packet loss: 0% (20/20)     Average delay 1 (low: 1 high: 1) 

Now here's a look at an SNMP walk of the Cisco ping MIB (note that we ftp'ed the Cisco ping MIB and placed it in the same folder with the rest of the Net-SNMP MIBs):

     $ snmpwalk -m ALL -IR -v1 -c public 192.168.0.130 ciscoPingMIB     CISCO-PING-MIB::ciscoPingProtocol.333 = INTEGER: ip(1)     CISCO-PING-MIB::ciscoPingAddress.333 = STRING: c0:a8:0:30     CISCO-PING-MIB::ciscoPingPacketCount.333 = INTEGER: 20     CISCO-PING-MIB::ciscoPingPacketSize.333 = INTEGER: 150     CISCO-PING-MIB::ciscoPingPacketTimeout.333 = INTEGER: 2000 milliseconds     CISCO-PING-MIB::ciscoPingDelay.333 = INTEGER: 0 milliseconds     CISCO-PING-MIB::ciscoPingTrapOnCompletion.333 = INTEGER: false(2)     CISCO-PING-MIB::ciscoPingSentPackets.333 = Counter32: 20     CISCO-PING-MIB::ciscoPingReceivedPackets.333 = Counter32: 20     CISCO-PING-MIB::ciscoPingMinRtt.333 = INTEGER: 1 milliseconds     CISCO-PING-MIB::ciscoPingAvgRtt.333 = INTEGER: 1 milliseconds     CISCO-PING-MIB::ciscoPingMaxRtt.333 = INTEGER: 1 milliseconds     CISCO-PING-MIB::ciscoPingCompleted.333 = INTEGER: true(1)     CISCO-PING-MIB::ciscoPingEntryOwner.333 = STRING: kjs     CISCO-PING-MIB::ciscoPingEntryStatus.333 = INTEGER: active(1) 

To summarize, this script does the following:

  1. Processes the ipsToPing hash by first destroying (as a just-in-case) and creating a new row in the table

  2. Sleeps to give the router time to do its job

  3. Gathers the results from the router, and deletes each row from the table

One enhancement that can be made is to persist each row to the table and let the router continually ping the target or targets. This could be accomplished by creating new entries on the router and setting the following OID:

     ciscoPingDelay OBJECT-TYPE             SYNTAX     Integer32 (0..3600000)             UNITS      "milliseconds"             MAX-ACCESS read-create             STATUS     current             DESCRIPTION                     "Specifies the minimum amount of time to wait before sending                     the next packet in a sequence after receiving a response or                     declaring a timeout for a previous packet.  The actual delay                     may be greater due to internal task scheduling."             DEFVAL { 0 }             ::= { ciscoPingEntry 7 } 

As the DESCRIPTION notes, ciscoPingDelay specifies a sort of sleep. The router will wait for the specified amount of time (in milliseconds) before it tries to ping the target again. Of course, you would also not want to destroy each row after you get the statistics from the routers, as is done in the earlier script.

Here are a couple of things to watch out for if you use this method:

  • If you are the only one using the router to perform pings, creating unique row values is controlled by one person. If more than one person uses the router, you run the risk of stepping on each other's toes if someone picks the same unique row number as you.

  • The router can reschedule these pings if it needs to. In other words, if it comes down to the router performing a routing function over a ping function, it's going to pick the routing function.




Essential SNMP
Essential SNMP, Second Edition
ISBN: 0596008406
EAN: 2147483647
Year: 2003
Pages: 165

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net