Cisco CBWFQ support

Anything that you think should be in Cacti.

Moderators: Developers, Moderators

Post Reply
ddehnke
Posts: 1
Joined: Mon Jan 26, 2004 12:15 pm
Contact:

Cisco CBWFQ support

Post by ddehnke »

One template with underlying support that I would love to see is support for Cisco's Classed Based Queueing. Being able to graph an interface separated by classes would really aid in being able to determine how close one would be getting to oversubscribing a particular class off traffic. I think that the underlying problem is that the index number change per configuration change so simply mapping the OUI values statically would not work.

I've done some work internally developing query tools to get the data, and I've seen this tool on sourceforge
http://sourceforge.net/docman/display_d ... p_id=25401


Has any thought been placed on adding this?
Guest

Post by Guest »

I am also looking for some solution but have done almost no testing till now. I think i will be writing some extension of sourceforge script and maybe modify it into cacty templates. What index is changing after each config change and what did you find out more testing with the cbwfq mib.
janno
Posts: 4
Joined: Fri Mar 26, 2004 3:45 pm

Post by janno »

Anonymous wrote:I am also looking for some solution but have done almost no testing till now. I think i will be writing some extension of sourceforge script and maybe modify it into cacty templates. What index is changing after each config change and what did you find out more testing with the cbwfq mib.
Sorry i forgot to login. It's me, Janno
janno
Posts: 4
Joined: Fri Mar 26, 2004 3:45 pm

Post by janno »

I have been programming a bit and it seems i can find and combine all info for cbwfq with snmp. But i wonder if i can get it working with Cacti. It is mabe my lack of cacti knowledge but the data which should be reported is so diverse that i think a simple data query will not work.

For every (sub)interface where qos is enabled i get a service policy
For every service policy i get some classes
For every class i get a bunch of policy's (shaping/queuing etc)
Depending in the type of policy i need different data collection and graph's

I think i can not do this with Cacti. Just using plain rrd will work but i would rather use Cacti.

Maybe i can do the opposite. Make different templates for every type of policy. Like a template for queuing, another template for policying etc. But this would mean a lot of work configuring a device and it would not be logical for the user. A user will always think starting from interfaces->service-policy->classes->policies->counters

In fact, all above is more complicated because it is also possible to use hiarchical service-policy's. Maybe it is possible to setup all measurements/graphs outside of cacti but managing them from whithin cacti.

To be continued...
User avatar
bulek
Cacti Pro User
Posts: 854
Joined: Mon May 20, 2002 2:07 am
Location: Poland
Contact:

Post by bulek »

Agree... it is quite complicated hierarchy. You can't do it using just simple SNMP query because every object is indexed with two values so the only solution is script based. I was involved some time ago with related task (external script). I found another problem which is even more important. Every change you do to your QoS settings implicates change in object SNMP indexes. In my network at least such changes are quite frequent. The script then should use interface name and calss map name as quite fixed parameters. Then do all mappings every poll and gather actual data. Small example follows (sorry... can't share the code :-( ).

- Piotr
Attachments
QoS graph example
QoS graph example
qos_graph.gif (24.03 KiB) Viewed 15407 times
janno
Posts: 4
Joined: Fri Mar 26, 2004 3:45 pm

Post by janno »

Thanks for the feedback. I am already working on the script. Did you only have problems with changing interface id's or also with the policy's and classes? I think i will be using ccmHistoryRunningLastChanged (1.3.6.1.4.1.9.9.43.1.1.1) as a trigger for reindexing the id's. Any other tips or code to share? :P
User avatar
bulek
Cacti Pro User
Posts: 854
Joined: Mon May 20, 2002 2:07 am
Location: Poland
Contact:

Post by bulek »

I am refering to changing QoS objects IDs only - whatever you change in parameters Cisco internaly deletes the object instance and creates a new one with new index and new parameters. I avoided interfaces IDs changing by using "snmp-server ifindex persist" command. Monitoring ccmHistoryRunningLastChanged status is very good idea... I was doing reindexing before every poll what was not too efficient. Since you will fetch quite a lot of tables during this process I would suggest using snmpbulkwalk which is much faster than snmpwalk. Good luck! :-)

- Piotr
carlos

CBWFQ on Cisco Routers

Post by carlos »

Seems that "Get SNMP Data" is the easiest way to read out the CBWFQ results. I find out the right indexes in 3 steps:

snmpwalk -c public -v 2c 10.10.10.10 ifdesc
snmpwalk -c public -v 2c 10.10.10.10 .1.3.6.1.4.1.9.9.166.1.1.1.1.4
snmpwalk -c public -v 2c 10.10.10.10 .1.3.6.1.4.1.9.9.166.1.15.1.1.10.x

First step: Look for the IF-index on which CBWFQ resides. e.g. "9"

Second: Search the CBWFQ-index "x" e.g. for interface 9
.1.3.6.1.4.1.9.9.166.1.1.1.1.4.x = 9

Third: Do some "snmp-walk" with .1.3.6.1.4.1.9.9.166.1.15.1.1.10.x and get as a result e.g.:

.1.3.6.1.4.1.9.9.166.1.15.1.1.10.1133.1137
.1.3.6.1.4.1.9.9.166.1.15.1.1.10.1133.1143
.1.3.6.1.4.1.9.9.166.1.15.1.1.10.1133.1149
.1.3.6.1.4.1.9.9.166.1.15.1.1.10.1133.1155
.1.3.6.1.4.1.9.9.166.1.15.1.1.10.1133.1161

where x = 1133.

For every of theses indexes an "SNMP GET"-Data source has to be created. Thats all.

In our CBWFQ - implementation we have the following index meanings (it´s a top-level policy)

1. index = voice
2. index = delay
3. index = best_effort
4. index = low_loss
5. index = summarized traffic

Indexes are listed by snmpwalk in the same order as shown on the Cisco Command Line Interface when typing "show policy interface" and can by easily adopted.

You guys are right, that a special php-script has to be written for that process.

Suddenly I´m not the php expert for that, but I´ll try to help you further on....
pwozney
Posts: 32
Joined: Thu Dec 16, 2004 3:14 pm

Post by pwozney »

I have hacked the CBWFQ script from sourceforge so that it outputs in what I think is in a cacti compatible way. I removed some of the spurious stuff, like the ability to monitor more than one router and output to rrd.

The output looks like this:

Code: Select all

# ./nmiscbwfq.pl 192.168.1.1 public
class-default:73257 class1:2803130392 class2:3988434683
The code:

Code: Select all

#!/usr/bin/perl

#Class-based weighted fair queue interrogation module.
#This module maps class names to policy-id, object-id pairs and
#does an SNMP get on the bytes transmitted OID.
#written by Andy Brauer
#initial release 07/05/2002
#current release 10/05/2002
#current version 0.51

use warnings;
use strict;

my @cb_config1;
my @arraypol;
my @arraypol1;
my @arrayconf;
my @arrayconf1;
my @arrayname;
my @arraypol3;
my @arrayobj;
my @array1stresult;
my @array2ndresult;
my @options;
my $line;
my $name_cell;
my $config_id1_cell;
my $config_id2_cell;
my $pol_id_cell;
my $obj_id_cell;
my $database;
my $node;
my $community;
my $class;
my @name;
my $newline;

#open, read and close config file;
@cb_config1 = @ARGV;
$node = $cb_config1[0];
$community = $cb_config1[1];
if ($node) {
if ($community) {
chomp $node;
chomp $community;
#call external app snmpwalk
#walk the CBWFQ config mib
#place result in "arrayconfig" array
@arrayconf = `/usr/bin/snmpwalk -v 2c $node -c $community 1.3.6.1.4.1.9.9.166.1.7.1.1.1`;
#call external app snmpwalk
#walk the CBWFQ policy mib
#place result in "arraypol" array
@arraypol = `/usr/bin/snmpwalk -v 2c $node -c $community 1.3.6.1.4.1.9.9.166.1.5.1.1.2`;
#step through "arrayconf" array and set each instance to the
foreach $line (@arrayconf)
{
        #replace the  ""new-line" character combination with a "new-line character".
        #this removes the trailing double-apostrophe from the result in the
        #"array-conf" array.
        $line =~ s/\"\n/\n/g;
        #replace double-apostrophe character with a period.
        #this removes the leading double-apostrophe from the result in the
        #"array-conf" array.
        $line =~ s/\"/./g;
        #replace all spaces with a period.
                $line =~ s/ /./g;
                #create a new array, "arrayconf1", with each child variable initialized to the value
                #of the "$line value" variable split by the period.
                @arrayconf1 = split(/\./,$line);
        $newline = $line;
        $newline =~ s/\.//g;
        @name = split (/:/, $newline);
        $class = $name[-1];
        chomp $class;
        print "$class:";
                #set the variable of the 13th "arrayconf1" array child variable to the "$name_cell"
                #variable.
        $name_cell = $arrayconf1[12];
        #remove the "new-line character"
        chomp $name_cell;
        #set the variable of the 10th "arrayconf1" array child variable to the "$config_id1_cell"
                #variable.
        $config_id1_cell = $arrayconf1[9];
        #step through the "arraypol" array and set each instance to the variable "$line"
        foreach $line (@arraypol)
        {
                #replace all spaces with a period.
                $line =~ s/ /./g;
                #create a new array, "arraypol1", with each child variable initialized to the value
                        #of the "$line value" variable split by the period.
                        @arraypol1 = split(/\./,$line);
                #set the variable of the 10th "arraypol1" array child variable to the "$pol_id_cell"
                        #variable.
                $pol_id_cell = $arraypol1[9];
                #set the variable of the 11th "arraypol1" array child variable to the "$obj_id_cell"
                        #variable.
                $obj_id_cell = $arraypol1[10];
                #set the variable of the 14th "arraypol1" array child variable to the "$conf_id2_cell"
                        #variable.
                $config_id2_cell = $arraypol1[13];
                #compare the value of variables "$config_id1_cell" and "$config_id2_cell".
                if($config_id1_cell == $config_id2_cell)
                {
                        #if the config_ids match then add the name to the name array, the pol_id
                        #to the pol_id array and the obj_id to the obj_id array.
                        @arrayname = $name_cell;
                        @arraypol3 = $pol_id_cell;
                        @arrayobj = $obj_id_cell;
                        #Step through the "@arrayname" array and set each instance to the "$name_cell"
                        #variable
                        foreach $name_cell (@arrayname)
                        {
                                #call external app snmpget and pass the values of the polid and objid variables. place the
                                #result in @array1stresult.
                                @array1stresult = `/usr/bin/snmpget -v 2c $node -c $community 1.3.6.1.4.1.9.9.166.1.15.1.1.9.$arraypol3[0].$arrayobj[0]`;
                                foreach $line (@array1stresult)
                                {
                                        #replace all spaces with a period.
                                        $line =~ s/ /./g;
                                        #create a new array, "array2ndresult", with each child variable initialized to the value
                                                #of the "$line" variable split by the period.
                                        @array2ndresult = split(/\./,$line);
                                        $newline = $line;
                                        $newline =~ s/\.//g;
                                        @name = split (/:/, $newline);
                                        $class = $name[-1];
                                        chomp $class;
                                        print "$class ";
                                }
                        }
                }
        }
};
};
}
pwozney
Posts: 32
Joined: Thu Dec 16, 2004 3:14 pm

Post by pwozney »

I have rewritten the script to be a little more readable, and it follows the cacti output standard.

Code: Select all

#!/usr/bin/perl

#Class-based weighted fair queue interrogation module.
#This module maps class names to policy-id, object-id pairs and
#does an SNMP get on the bytes transmitted OID.
#written by Andy Brauer
#initial release 07/05/2002
#current release 10/05/2002
#current version 0.51
#
# 25/04/2005 - Paul Wozney
#
# Completely rewritten by Paul Wozney
# There was nothing really wrong with the script that Andy wrote,
# but I extended it to respond to index, query and get requests
# and made seperate subroutines for these
#
# I did this so I could integrate the script into cacti, as this
# was the only script available - and I really couldn't follow
# the code that Andy wrote so I figured it was easier just to
# do it my way.  :)
#
# I'm sure there are bugs.  Reach me here: 
#
# One caveat, as I'm currently applying DSCP and policing QoS on
# the same router I named my QoS classes like this "QoSnnnn" and
# this script is written to see those.

#use warnings;
use strict;

my $ip = $ARGV[0];
my $community = $ARGV[1];
my $action = $ARGV[2];
my $class = $ARGV[3];
my $filterstring = "QoS";       # use this to filter out unwanted classes
#my $filterstring = ".*";       # or to match everything

my $snmppath = "/usr/bin/snmpwalk";
my $version = "2c";
my $index_oid = "1.3.6.1.4.1.9.9.166.1.7.1.1.1";        # lists the classes
my $ilist_oid = "1.3.6.1.4.1.9.9.166.1.5.1.1.2";        # lists the references
my $bytes_oid = "1.3.6.1.4.1.9.9.166.1.15.1.1.9";       # lists the pol/obj id refs

sub retrieve_index {

# lists the classes
# this is used in the other subroutines, so if a third variable is passed "index"
# it lists the references along with the classes

        my $node = shift;
        my $comm = shift;
        my $ind = shift;
        my @classes;

        my @index = `$snmppath -v $version $node -c $comm $index_oid`;
        # should output this:
        # SNMPv2-SMI::enterprises.9.9.166.1.7.1.1.1.1025 = STRING: "CLASS"

        foreach (@index) {
                s/"//g;
                my @littlearray = split / /;
                # if you've set $filterstring it will only display those classes you want
                next unless ($littlearray[3] =~ /$filterstring/);
                my @values = split /\./, $littlearray[0];
                if ($ind eq "index") { push @classes, "$littlearray[3]:$values[9]" ; }
                else { push @classes, $littlearray[3]; }
        }
        return @classes;
}

sub retrieve_query {

# retrieves the bytes for all classes

        my $node = shift;
        my $comm = shift;
        my @classes = @_;       # gets the remaining variables passed
        my @bytes;

        my @ilist = `$snmppath -v $version $node -c $comm $ilist_oid`;
        # should output this:
        # SNMPv2-SMI::enterprises.9.9.166.1.5.1.1.2.1073.1073 = Gauge32: 1025
        # note that the variable part matches the oid for the class above

        foreach my $entry (@ilist) {
                my @littlearray = split / /, $entry;
                my @values = split /\./, $littlearray[0];
                chomp $littlearray[3];
                foreach (@classes) {
                        my ($class,$refer) = split /:/;
                        chomp $refer;
                        chomp $class;
                        # if you've set $filterstring it will only display those classes you want
                        if (($littlearray[3] eq $refer) && ($class =~ /$filterstring/)) {
                                my $byte_count = `$snmppath -v $version $node -c $comm $bytes_oid.$values[9].$values[10]`;
                                my @byte_array = split / /, $byte_count;
                                push @bytes, "$class:$byte_array[3]";
                        }
                }
        }
        return @bytes;
}

sub retrieve_get {

# gets the bytes for a single class
# this executes in about 10 seconds on my box, it could be
# way faster if there was some kind of caching done, maybe
# expire after an hour considering most people poll every 5 mins

        my $node = shift;
        my $comm = shift;
        my $colour = shift;     # just another variable for class, but
                                # I hate scope problems.  :)
        chomp $colour;
        my @classes = @_;
        my $ival;
        my $indexval;

        my @ilist = `$snmppath -v $version $node -c $comm $ilist_oid`;

        # first figure out the reference for the class
        foreach (@classes) {
                my ($class,$refer) = split /:/;
                chomp $class;
                chomp $refer;
                if ($colour eq $class) { $ival = $refer; }
        }

        # then figure out the oid
        foreach my $entry (@ilist) {
                my @littlearray = split / /, $entry;
                my @values = split /\./, $littlearray[0];
                chomp $littlearray[3];
                if ($ival eq $littlearray[3]) { $indexval = "$values[9].$values[10]" ; }
        }

        # and POW!  it's done.
        my $byte_count = `$snmppath -v $version $node -c $comm $bytes_oid.$indexval`;
        my @byte_array = split / /, $byte_count;

        return "$class:$byte_array[3]";
}

ARGUMENTS: {
        if ($action eq "index") { print retrieve_index($ip,$community) ; last ARGUMENTS; }
        if ($action eq "query") { print retrieve_query($ip,$community,retrieve_index($ip,$community,"index")) ; last ARGUMENTS; }
        if ($action eq "get") { print retrieve_get($ip,$community,$class,retrieve_index($ip,$community,"index")) ; last ARGUMENTS; }
        print "usage:\n\n./nmiscbwfq.pl IP COMMUNITY index\n./nmiscbwfq.pl IP COMMUNITY query {bytes}\n./nmiscbwfq.pl IP COMMUNITY get {bytes} CLASS\n";
}

exit;
Last edited by pwozney on Tue Apr 26, 2005 11:40 am, edited 1 time in total.
pwozney
Posts: 32
Joined: Thu Dec 16, 2004 3:14 pm

Post by pwozney »

Success!

Now all I need to do is put the lines on the same graph.
Attachments
cacti_data_query_cisco_get_cbwfq_classes.xml
(10.5 KiB) Downloaded 486 times
cacti_data_template_cbwfq_throughput.xml
(4.33 KiB) Downloaded 556 times
cacti_graph_template_cisco_bits_output_from_qos_class.xml
(9 KiB) Downloaded 612 times
pwozney
Posts: 32
Joined: Thu Dec 16, 2004 3:14 pm

Post by pwozney »

The last template and the updated script - I have made changes since yesterday.
Attachments
cacti_host_template_cisco_router.xml
(123.84 KiB) Downloaded 655 times
cbwfq.txt
(6.06 KiB) Downloaded 774 times
pwozney
Posts: 32
Joined: Thu Dec 16, 2004 3:14 pm

Post by pwozney »

Since I have managed to get this working, I recommend that you follow the thread here if you want to hear about my work on this little problem:

http://forums.cacti.net/viewtopic.php?t=7401
Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests