Beginning in version 10, the snmp mibs provide pre-calculated cpu utilization percentages for 5 second, 1 minute, and 5 minute intervals.  This eases the processing burden on the Cacti end, as with these oid we only need to reach out once per interval for data from the BIG-IP.  I'm getting ahead of myself, though.  We've created a data query with an indexed SNMP data query file in an earlier tech tip, this time we'll create a scripted data input method.

SNMP MIB Information

The oids we'll use in to build this template are pre-calculated (and in the table below).  There are an expansive list of other oids if you'd like to do the calculations yourself, just check out the v.10 TMOS Management Guide for BIG-IP Systems.

OID name OID String
sysMultiHostCpuIndex .1.3.6.1.4.1.3375.2.1.7.5.2.1.2
sysMultiHostCpuUsageRatio5s .1.3.6.1.4.1.3375.2.1.7.5.2.1.19
sysMultiHostCpuUsageRatio1m .1.3.6.1.4.1.3375.2.1.7.5.2.1.26
sysMultiHostCpuUsageRatio5m .1.3.6.1.4.1.3375.2.1.7.5.2.1.35
sysGlobalHostCpuUsageRatio5s .1.3.6.1.4.1.3375.2.1.1.2.20.21
sysGlobalHostCpuUsageRatio1m .1.3.6.1.4.1.3375.2.1.1.2.20.29
sysGlobalHostCpuUsageRatio5m .1.3.6.1.4.1.3375.2.1.1.2.20.37

 

Data Collection Perl Script

All the newer BIG-IP platforms have multiple processors, or single processors with multiple cores, and so we need the cpu index to iterate through the oids to collect the statistics for each processor.  The perl script below utilizes the oids above to query the BIG-IP and display the current utilization for the individual cpu's and the global host utilization.  There are two flavors for this script.  The first is for usage on the command line, so the output is a little prettier.  The second is the one we'll use for cacti, which must print in a value-pair list separated by a space.

CPU Utilization for CLI Usage
#!/usr/bin/perl -w
# This code is not supported by F5 Network and is offered under the GNU General Public License.  Use at your own risk.
use strict;
use Net::SNMP qw(:snmp);

my ($host, $snmp_comm);
$host = $ARGV[0];
$snmp_comm = $ARGV[1];
chomp ($host , $snmp_comm);

my $cpuIndex     = ".1.3.6.1.4.1.3375.2.1.7.5.2.1.2.1.48";

my $cpuUsageRatio5s = ".1.3.6.1.4.1.3375.2.1.7.5.2.1.19.1.48.";
my $cpuUsageRatio1m = ".1.3.6.1.4.1.3375.2.1.7.5.2.1.27.1.48.";
my $cpuUsageRatio5m = ".1.3.6.1.4.1.3375.2.1.7.5.2.1.35.1.48.";

my $gcpuUsageRatio5s = ".1.3.6.1.4.1.3375.2.1.1.2.20.21.0";
my $gcpuUsageRatio1m = ".1.3.6.1.4.1.3375.2.1.1.2.20.29.0";
my $gcpuUsageRatio5m = ".1.3.6.1.4.1.3375.2.1.1.2.20.37.0";

my ($session, $error) = Net::SNMP->session(
     -hostname       => $host,
     -community      => $snmp_comm,
     -port           => 161,
     -version        => 'snmpv2c',
     -nonblocking    => 0
);

if (!defined $session) {
     print "Received no SNMP response from $host\n";
     print STDERR "Error: $error\n";
exit -1;
}

my $allCPU = $session->get_table ( -baseoid => $cpuIndex );
my %cpu_table = %{$allCPU};
my $x = 0;
print "\n\nCPU Utilization:\t5s\t1m\t5m\n\n";

foreach my $key (sort keys %cpu_table) {
     my @oid_index = split(/\./, $key);

     my $ltm_cpu5s = $cpuUsageRatio5s . $oid_index[-1];
     my $ltm_cpu1m = $cpuUsageRatio1m . $oid_index[-1];
     my $ltm_cpu5m = $cpuUsageRatio5m . $oid_index[-1];

     my $oid_ratios = $session->get_request(
          -varbindlist =>
          [$ltm_cpu5s, $ltm_cpu1m, $ltm_cpu5m] );
     print "\tCPU$x\t\t$oid_ratios->{$ltm_cpu5s}\t$oid_ratios->{$ltm_cpu1m}\t$oid_ratios->{$ltm_cpu5m}\n";
     $x++;
}

my $oid_gratios = $session->get_request(
     -varbindlist =>
     [$gcpuUsageRatio5s, $gcpuUsageRatio1m, $gcpuUsageRatio5m] );

print "\tGlobal\t\t$oid_gratios->{$gcpuUsageRatio5s}\t$oid_gratios->{$gcpuUsageRatio1m}\t$oid_gratios->{$gcpuUsageRatio5m}\n\n\n";

 

CPU Utilization for Cacti Usage
#!/usr/bin/perl -w
# This code is not supported by F5 Network and is offered under the GNU General Public License.  Use at your own risk.
#use strict;
use Net::SNMP qw(:snmp);

my ($host, $snmp_comm);
$host = $ARGV[0];
$snmp_comm = $ARGV[1];
chomp ($host , $snmp_comm);

my $cpuIndex     = ".1.3.6.1.4.1.3375.2.1.7.5.2.1.2.1.48";

my $cpuUsageRatio5s = ".1.3.6.1.4.1.3375.2.1.7.5.2.1.19.1.48.";
my $cpuUsageRatio1m = ".1.3.6.1.4.1.3375.2.1.7.5.2.1.27.1.48.";
my $cpuUsageRatio5m = ".1.3.6.1.4.1.3375.2.1.7.5.2.1.35.1.48.";

my $gcpuUsageRatio5s = ".1.3.6.1.4.1.3375.2.1.1.2.20.21.0";
my $gcpuUsageRatio1m = ".1.3.6.1.4.1.3375.2.1.1.2.20.29.0";
my $gcpuUsageRatio5m = ".1.3.6.1.4.1.3375.2.1.1.2.20.37.0";

my ($session, $error) = Net::SNMP->session(
     -hostname       => $host,
     -community      => $snmp_comm,
     -port           => 161,
     -version        => 'snmpv2c',
     -nonblocking    => 0
);

if (!defined $session) {
     print "Received no SNMP response from $host\n";
     print STDERR "Error: $error\n";
     exit -1;
}

my $allCPU = $session->get_table ( -baseoid => $cpuIndex );
my %cpu_table = %{$allCPU};
my $x = 0;

foreach my $key (sort keys %cpu_table) {
     @oid_index = split(/\./, $key);
     my $ltm_cpu5s = $cpuUsageRatio5s . $oid_index[-1];
     my $ltm_cpu1m = $cpuUsageRatio1m . $oid_index[-1];
     my $ltm_cpu5m = $cpuUsageRatio5m . $oid_index[-1];

     my $oid_ratios = $session->get_request(
          -varbindlist =>
          [$ltm_cpu5s, $ltm_cpu1m, $ltm_cpu5m] );

     print "CPU$x\_5s:$oid_ratios->{$ltm_cpu5s} CPU$x\_1m:$oid_ratios->{$ltm_cpu1m} CPU$x\_5m:$oid_ratios->{$ltm_cpu5m} ";
     $x++;
}

my $oid_gratios = $session->get_request(
     -varbindlist =>
     [$gcpuUsageRatio5s, $gcpuUsageRatio1m, $gcpuUsageRatio5m] );

print "Global_5s:$oid_gratios->{$gcpuUsageRatio5s} Global_1m:$oid_gratios->{$gcpuUsageRatio1m} Global_5m:$oid_gratios->{$gcpuUsageRatio5m}";

We need to place the script (in my case named f5_bigip_cpun.pl) in the Cacti scripts directory.  On my system, this is /var/www/html/cacti/scripts.

CPU Utilization Generator

As an aside, I want to have something actually hitting the processors so we don't have an empty graph when we're done.  For this, one of F5's excellent FSE's whipped this iRule together to challenge the cpus (make sure you set your TCP profile idle timeout to indefinite, oh, and don't run this on a production system!):

CPU Workout iRule
when CLIENT_ACCEPTED {
     after 1 -periodic {
          set i 0
          while { $i < 150 } {   
               sha512 [expr [expr 188888 * rand()] / 8675309]
               incr i
          } 
     }
     TCP::collect
}

 

OK, all the prep work is done, now to Cacti to finish out the work.

Cacti Data Input Method

First, we build the data input method.  The input type is Script/Command, and the input string is the command that Cacti should run, including options.  In this case, it's "perl <path_cacti>/scripts/f5_bigip_cpun.pl <hostname> <snmp_community>".  After saving, we can add the input and output fields. 

 Figure 1. Data Input Method - Top
Level

The input fields are the <hostname> and <snmp_community> options.  For each input, we'll select from the drop down, give it a friendly name, then set the appropriate special type code.

 Figure 2. Data Input Method - Input
Field

 

 

 

 

 

  Next we add the output fields. The names should match the field output from the script.

Figure 3. Data Input Method -
Output Field

 

 

 

 

 

 Cacti Data Template

After creating the data input method, we can create the data template.  We select the data input method we created, create a unique but representative name for our data source items, then select the appropriate output field from our data input method.  Creating the nine data source items is a patience builder, as each save exits the template, requiring us to re-enter the template after each save to create a new data source item.

Figure 4. Data Template

Cacti Graph Template

Now that all our data source items are in place, we can create the graph template.  Because we have a lot of information in our graph, we'll expand from the default size to 750x200.

Figure 5. Graph Template - Options

After saving, now we can add our data source items to be graphed.  For this effort, we'll make CPU0 graph positive from 0 and CPU1 graph negative (accomplished by using the built-in CDEF "Make Stack Negative").  For both processors, we'll use a green area for 5 minute utilization, a blue line for 1 minute utilization, and a black line for 5 second utilization.

Figure 6. Graph Template - Data Source
Items

Here's how the "Make Stack Negative" is selected while adding a graph item to the graph template.

Figure 7. Graph Template - Make
Stack Negative

Final Results

Now that the template is built, the cpu stressor iRule is running, and Cacti is polling, our graph is functioning as expected.  Note that if you have a system with more than two processors, you might alter the template to put a single processor in the graph or stack them, or perhaps just graph the 5min interval so the graph doesn't get to cluttered.  The graph template and script have been added to the F5 BIG-IP host template.  Installation instructions are here in the wiki.  Check out this DCTV tutorial for video coverage of the Cacti template creation.

Figure 8. CPU Graph Output