mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Cisco CBQOS
Implements the CISCO-CLASS-BASED-QOS-MIB to retrieve QOS counters from Cisco devices. Policy and Class-map details are collected and stored in the database. Details are presented on a new "CBQoS" tab of the interface that the policy is applied to. Includes a policy selector that allows you to select which policy-map to show graphs for. Each class-map has its own rrd file, in which 3 metrics are stored: Bytes, QoS Drops, Buffer Drops. This can produce a LOT of rrd files. As an example: A Cisco 4500 series switch, running MQC on 200 ports. Each port has a common 5 class queueing policy applied, this creates 1000 (5 x 200) RRD's. Because of this I have currently set: ``` $config['discovery_modules']['cisco-cbqos'] = 0; ``` Includes function snmpwalk_array_num, which performs a numeric SNMPWalk and returns an array containing $count indexes One Index: From: 1.3.6.1.4.1.9.9.166.1.15.1.1.27.18.655360 = 0 To: $array['1.3.6.1.4.1.9.9.166.1.15.1.1.27.18']['655360'] = 0 Two Indexes: From: 1.3.6.1.4.1.9.9.166.1.15.1.1.27.18.655360 = 0 To: $array['1.3.6.1.4.1.9.9.166.1.15.1.1.27']['18']['655360'] = 0 And so on...
This commit is contained in:
@@ -710,6 +710,7 @@ $config['poller_modules']['applications'] = 1;
|
||||
$config['poller_modules']['cisco-asa-firewall'] = 1;
|
||||
$config['poller_modules']['mib'] = 0;
|
||||
$config['poller_modules']['cisco-voice'] = 1;
|
||||
$config['poller_modules']['cisco-cbqos'] = 1;
|
||||
$config['poller_modules']['stp'] = 1;
|
||||
|
||||
// List of discovery modules. Need to be in this array to be
|
||||
@@ -742,6 +743,7 @@ $config['discovery_modules']['toner'] = 1;
|
||||
$config['discovery_modules']['ucd-diskio'] = 1;
|
||||
$config['discovery_modules']['services'] = 1;
|
||||
$config['discovery_modules']['charge'] = 1;
|
||||
$config['discovery_modules']['cisco-cbqos'] = 0;
|
||||
$config['discovery_modules']['stp'] = 1;
|
||||
|
||||
$config['modules_compat']['rfc1628']['liebert'] = 1;
|
||||
|
||||
184
includes/discovery/cisco-cbqos.inc.php
Normal file
184
includes/discovery/cisco-cbqos.inc.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
/*
|
||||
* LibreNMS module to capture Cisco Class-Based QoS Details
|
||||
*
|
||||
* Copyright (c) 2015 Aaron Daniels <aaron@daniels.id.au>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version. Please see LICENSE.txt at the top level of
|
||||
* the source code distribution for details.
|
||||
*/
|
||||
|
||||
if ($device['os_group'] == 'cisco') {
|
||||
|
||||
$MODULE = 'Cisco-CBQOS';
|
||||
echo $MODULE.': ';
|
||||
|
||||
require_once 'includes/component.php';
|
||||
$COMPONENT = new component();
|
||||
$COMPONENTS = $COMPONENT->getComponents($device['device_id'],array('type'=>$MODULE));
|
||||
|
||||
// We only care about our device id.
|
||||
$COMPONENTS = $COMPONENTS[$device['device_id']];
|
||||
|
||||
|
||||
// Begin our master array, all other values will be processed into this array.
|
||||
$tblCBQOS = array();
|
||||
|
||||
// Let's gather some data..
|
||||
$tblcbQosServicePolicy = snmpwalk_array_num($device, '.1.3.6.1.4.1.9.9.166.1.1');
|
||||
$tblcbQosObjects = snmpwalk_array_num($device, '.1.3.6.1.4.1.9.9.166.1.5', 2);
|
||||
$tblcbQosPolicyMapCfg = snmpwalk_array_num($device, '.1.3.6.1.4.1.9.9.166.1.6');
|
||||
$tblcbQosClassMapCfg = snmpwalk_array_num($device, '.1.3.6.1.4.1.9.9.166.1.7');
|
||||
$tblcbQosMatchStmtCfg = snmpwalk_array_num($device, '.1.3.6.1.4.1.9.9.166.1.8');
|
||||
|
||||
/*
|
||||
* False == no object found - this is not an error, there is no QOS configured
|
||||
* null == timeout or something else that caused an error, there may be QOS configured but we couldn't get it.
|
||||
*/
|
||||
if ( is_null($tblcbQosServicePolicy) || is_null($tblcbQosObjects) || is_null($tblcbQosPolicyMapCfg) || is_null($tblcbQosClassMapCfg) || is_null($tblcbQosMatchStmtCfg) ) {
|
||||
// We have to error here or we will end up deleting all our QoS components.
|
||||
echo "Error\n";
|
||||
}
|
||||
else {
|
||||
// No Error, lets process things.
|
||||
d_echo("QoS Objects Found:\n");
|
||||
|
||||
foreach ($tblcbQosObjects['1.3.6.1.4.1.9.9.166.1.5.1.1.2'] as $spid => $array) {
|
||||
|
||||
foreach ($array as $spobj => $index) {
|
||||
$RESULT = array();
|
||||
|
||||
// Produce a unique reproducible index for this entry.
|
||||
$RESULT['UID'] = hash('crc32', $spid."-".$spobj);
|
||||
|
||||
// Now that we have a valid identifiers, lets add some more data
|
||||
$RESULT['sp-id'] = $spid;
|
||||
$RESULT['sp-obj'] = $spobj;
|
||||
|
||||
// Add the Type, Policy-map, Class-map, etc.
|
||||
$type = $tblcbQosObjects['1.3.6.1.4.1.9.9.166.1.5.1.1.3'][$spid][$spobj];
|
||||
$RESULT['qos-type'] = $type;
|
||||
|
||||
// Add the Parent, this lets us work out our hierarchy for display later.
|
||||
$RESULT['parent'] = $tblcbQosObjects['1.3.6.1.4.1.9.9.166.1.5.1.1.4'][$spid][$spobj];
|
||||
$RESULT['direction'] = $tblcbQosServicePolicy['1.3.6.1.4.1.9.9.166.1.1.1.1.3'][$spid];
|
||||
$RESULT['ifindex'] = $tblcbQosServicePolicy['1.3.6.1.4.1.9.9.166.1.1.1.1.4'][$spid];
|
||||
|
||||
// Gather different data depending on the type.
|
||||
switch ($type) {
|
||||
case 1:
|
||||
// Policy-map, get data from that table.
|
||||
d_echo("\nIndex: ".$index."\n");
|
||||
d_echo(" UID: ".$RESULT['UID']."\n");
|
||||
d_echo(" SPID.SPOBJ: ".$RESULT['sp-id'].".".$RESULT['sp-obj']."\n");
|
||||
d_echo(" If-Index: ".$RESULT['ifindex']."\n");
|
||||
d_echo(" Type: 1 - Policy-Map\n");
|
||||
$RESULT['label'] = $tblcbQosPolicyMapCfg['1.3.6.1.4.1.9.9.166.1.6.1.1.1'][$index];
|
||||
if ($tblcbQosPolicyMapCfg['1.3.6.1.4.1.9.9.166.1.6.1.1.2'][$index] != "") {
|
||||
$RESULT['label'] .= " - ".$tblcbQosPolicyMapCfg['1.3.6.1.4.1.9.9.166.1.6.1.1.2'][$index];
|
||||
}
|
||||
d_echo(" Label: ".$RESULT['label']."\n");
|
||||
break;
|
||||
case 2:
|
||||
// Class-map, get data from that table.
|
||||
d_echo("\nIndex: ".$index."\n");
|
||||
d_echo(" UID: ".$RESULT['UID']."\n");
|
||||
d_echo(" SPID.SPOBJ: ".$RESULT['sp-id'].".".$RESULT['sp-obj']."\n");
|
||||
d_echo(" If-Index: ".$RESULT['ifindex']."\n");
|
||||
d_echo(" Type: 2 - Class-Map\n");
|
||||
$RESULT['label'] = $tblcbQosClassMapCfg['1.3.6.1.4.1.9.9.166.1.7.1.1.1'][$index];
|
||||
if($tblcbQosClassMapCfg['1.3.6.1.4.1.9.9.166.1.7.1.1.2'][$index] != "") {
|
||||
$RESULT['label'] .= " - ".$tblcbQosClassMapCfg['1.3.6.1.4.1.9.9.166.1.7.1.1.2'][$index];
|
||||
}
|
||||
d_echo(" Label: ".$RESULT['label']."\n");
|
||||
if ($tblcbQosClassMapCfg['1.3.6.1.4.1.9.9.166.1.7.1.1.3'][$index] == 2) {
|
||||
$RESULT['map-type'] = 'Match-All';
|
||||
}
|
||||
elseif ($tblcbQosClassMapCfg['1.3.6.1.4.1.9.9.166.1.7.1.1.3'][$index] == 3) {
|
||||
$RESULT['map-type'] = 'Match-Any';
|
||||
}
|
||||
else {
|
||||
$RESULT['map-type'] = 'None';
|
||||
}
|
||||
|
||||
// Find a child, this will be a type 3
|
||||
foreach ($tblcbQosObjects['1.3.6.1.4.1.9.9.166.1.5.1.1.4'][$spid] as $ID => $VALUE) {
|
||||
if ($VALUE == $RESULT['sp-obj']) {
|
||||
// We have our child, import the match
|
||||
if ($tblcbQosObjects['1.3.6.1.4.1.9.9.166.1.5.1.1.3'][$spid][$ID] == 3) {
|
||||
$RESULT['match'] = $RESULT['map-type'].": ".$tblcbQosMatchStmtCfg['1.3.6.1.4.1.9.9.166.1.8.1.1.1'][$tblcbQosObjects['1.3.6.1.4.1.9.9.166.1.5.1.1.2'][$spid][$ID]];
|
||||
d_echo(" Match: ".$RESULT['match']."\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue 2;
|
||||
}
|
||||
|
||||
$tblCBQOS[] = $RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, we have our 2 array's (Components and SNMP) now we need
|
||||
* to compare and see what needs to be added/updated.
|
||||
*
|
||||
* Let's loop over the SNMP data to see if we need to ADD or UPDATE any components.
|
||||
*/
|
||||
foreach ($tblCBQOS as $key => $array) {
|
||||
$COMPONENT_KEY = false;
|
||||
|
||||
// Loop over our components to determine if the component exists, or we need to add it.
|
||||
foreach ($COMPONENTS as $COMPID => $CHILD) {
|
||||
if ($CHILD['UID'] === $array['UID']) {
|
||||
$COMPONENT_KEY = $COMPID;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$COMPONENT_KEY) {
|
||||
// The component doesn't exist, we need to ADD it - ADD.
|
||||
$NEW_COMPONENT = $COMPONENT->createComponent($device['device_id'],$MODULE);
|
||||
$COMPONENT_KEY = key($NEW_COMPONENT);
|
||||
$COMPONENTS[$COMPONENT_KEY] = array_merge($NEW_COMPONENT[$COMPONENT_KEY], $array);
|
||||
echo "+";
|
||||
}
|
||||
else {
|
||||
// The component does exist, merge the details in - UPDATE.
|
||||
$COMPONENTS[$COMPONENT_KEY] = array_merge($COMPONENTS[$COMPONENT_KEY], $array);
|
||||
echo ".";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop over the Component data to see if we need to DELETE any components.
|
||||
*/
|
||||
foreach ($COMPONENTS as $key => $array) {
|
||||
// Guilty until proven innocent
|
||||
$FOUND = false;
|
||||
|
||||
foreach ($tblCBQOS as $k => $v) {
|
||||
if ($array['UID'] == $v['UID']) {
|
||||
// Yay, we found it...
|
||||
$FOUND = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($FOUND === false) {
|
||||
// The component has not been found. we should delete it.
|
||||
echo "-";
|
||||
$COMPONENT->deleteComponent($key);
|
||||
}
|
||||
}
|
||||
|
||||
// Write the Components back to the DB.
|
||||
$COMPONENT->setComponentPrefs($device['device_id'],$COMPONENTS);
|
||||
echo "\n";
|
||||
|
||||
} // End if not error
|
||||
|
||||
}
|
||||
72
includes/polling/cisco-cbqos.inc.php
Normal file
72
includes/polling/cisco-cbqos.inc.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/*
|
||||
* LibreNMS module to capture Cisco Class-Based QoS Details
|
||||
*
|
||||
* Copyright (c) 2015 Aaron Daniels <aaron@daniels.id.au>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version. Please see LICENSE.txt at the top level of
|
||||
* the source code distribution for details.
|
||||
*/
|
||||
|
||||
if ($device['os_group'] == "cisco") {
|
||||
|
||||
$MODULE = 'Cisco-CBQOS';
|
||||
|
||||
require_once 'includes/component.php';
|
||||
$COMPONENT = new component();
|
||||
$options['filter']['type'] = array('=',$MODULE);
|
||||
$options['filter']['disabled'] = array('=',0);
|
||||
$options['filter']['ignore'] = array('=',0);
|
||||
$COMPONENTS = $COMPONENT->getComponents($device['device_id'],$options);
|
||||
|
||||
// We only care about our device id.
|
||||
$COMPONENTS = $COMPONENTS[$device['device_id']];
|
||||
|
||||
// Only collect SNMP data if we have enabled components
|
||||
if (count($COMPONENTS > 0)) {
|
||||
// Let's gather the stats..
|
||||
$tblcbQosClassMapStats = snmpwalk_array_num($device, '.1.3.6.1.4.1.9.9.166.1.15.1.1', 2);
|
||||
|
||||
// Loop through the components and extract the data.
|
||||
foreach ($COMPONENTS as $KEY => $ARRAY) {
|
||||
$TYPE = $ARRAY['qos-type'];
|
||||
|
||||
// Get data from the class table.
|
||||
if ($TYPE == 2) {
|
||||
// Let's make sure the RRD is setup for this class.
|
||||
$filename = "port-".$ARRAY['ifindex']."-cbqos-".$ARRAY['sp-id']."-".$ARRAY['sp-obj'].".rrd";
|
||||
$rrd_filename = $config['rrd_dir'] . "/" . $device['hostname'] . "/" . safename ($filename);
|
||||
|
||||
if (!file_exists ($rrd_filename)) {
|
||||
rrdtool_create ($rrd_filename, " DS:postbits:COUNTER:600:0:U DS:bufferdrops:COUNTER:600:0:U DS:qosdrops:COUNTER:600:0:U" . $config['rrd_rra']);
|
||||
}
|
||||
|
||||
// Let's print some debugging info.
|
||||
d_echo("\n\nComponent: ".$KEY."\n");
|
||||
d_echo(" Class-Map: ".$ARRAY['label']."\n");
|
||||
d_echo(" SPID.SPOBJ: ".$ARRAY['sp-id'].".".$ARRAY['sp-obj']."\n");
|
||||
d_echo(" PostBytes: 1.3.6.1.4.1.9.9.166.1.15.1.1.10.".$ARRAY['sp-id'].".".$ARRAY['sp-obj']." = ".$tblcbQosClassMapStats['1.3.6.1.4.1.9.9.166.1.15.1.1.10'][$ARRAY['sp-id']][$ARRAY['sp-obj']]."\n");
|
||||
d_echo(" BufferDrops: 1.3.6.1.4.1.9.9.166.1.15.1.1.21.".$ARRAY['sp-id'].".".$ARRAY['sp-obj']." = ".$tblcbQosClassMapStats['1.3.6.1.4.1.9.9.166.1.15.1.1.21'][$ARRAY['sp-id']][$ARRAY['sp-obj']]."\n");
|
||||
d_echo(" QOSDrops: 1.3.6.1.4.1.9.9.166.1.15.1.1.17.".$ARRAY['sp-id'].".".$ARRAY['sp-obj']." = ".$tblcbQosClassMapStats['1.3.6.1.4.1.9.9.166.1.15.1.1.17'][$ARRAY['sp-id']][$ARRAY['sp-obj']]."\n");
|
||||
|
||||
$RRD['postbytes'] = $tblcbQosClassMapStats['1.3.6.1.4.1.9.9.166.1.15.1.1.10'][$ARRAY['sp-id']][$ARRAY['sp-obj']];
|
||||
$RRD['bufferdrops'] = $tblcbQosClassMapStats['1.3.6.1.4.1.9.9.166.1.15.1.1.21'][$ARRAY['sp-id']][$ARRAY['sp-obj']];
|
||||
$RRD['qosdrops'] = $tblcbQosClassMapStats['1.3.6.1.4.1.9.9.166.1.15.1.1.17'][$ARRAY['sp-id']][$ARRAY['sp-obj']];
|
||||
|
||||
// Update RRD
|
||||
rrdtool_update ($rrd_filename, $RRD);
|
||||
|
||||
// Clean-up after yourself!
|
||||
unset($filename, $rrd_filename);
|
||||
}
|
||||
} // End foreach components
|
||||
|
||||
echo $MODULE." ";
|
||||
} // end if count components
|
||||
|
||||
// Clean-up after yourself!
|
||||
unset($TYPE, $COMPONENTS, $COMPONENT, $options, $MODULE);
|
||||
}
|
||||
@@ -1268,4 +1268,70 @@ function register_mibs($device, $mibs, $included_by)
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
} // register_mibs
|
||||
|
||||
/**
|
||||
* SNMPWalk_array_num - performs a numeric SNMPWalk and returns an array containing $count indexes
|
||||
* One Index:
|
||||
* From: 1.3.6.1.4.1.9.9.166.1.15.1.1.27.18.655360 = 0
|
||||
* To: $array['1.3.6.1.4.1.9.9.166.1.15.1.1.27.18']['655360'] = 0
|
||||
* Two Indexes:
|
||||
* From: 1.3.6.1.4.1.9.9.166.1.15.1.1.27.18.655360 = 0
|
||||
* To: $array['1.3.6.1.4.1.9.9.166.1.15.1.1.27']['18']['655360'] = 0
|
||||
* And so on...
|
||||
* Think snmpwalk_cache_*_oid but for numeric data.
|
||||
*
|
||||
* Why is this useful?
|
||||
* Some SNMP data contains a single index (eg. ifIndex in IF-MIB) and some is dual indexed
|
||||
* (eg. PolicyIndex/ObjectsIndex in CISCO-CLASS-BASED-QOS-MIB).
|
||||
* The resulting array allows us to easily access the top level index we want and iterate over the data from there.
|
||||
*
|
||||
* @param $device
|
||||
* @param $OID
|
||||
* @param int $indexes
|
||||
* @internal param $string
|
||||
* @return array
|
||||
*/
|
||||
function snmpwalk_array_num($device,$OID,$indexes=1) {
|
||||
$array = array();
|
||||
$string = snmp_walk($device, $OID, '-Osqn');
|
||||
|
||||
if ( $string === false) {
|
||||
// False means: No Such Object.
|
||||
return false;
|
||||
}
|
||||
if ($string == "") {
|
||||
// Empty means SNMP timeout or some such.
|
||||
return null;
|
||||
}
|
||||
|
||||
// Let's turn the string into something we can work with.
|
||||
foreach (explode("\n", $string) as $line) {
|
||||
if ($line[0] == '.') {
|
||||
// strip the leading . if it exists.
|
||||
$line = substr($line,1);
|
||||
}
|
||||
list($key, $value) = explode(' ', $line, 2);
|
||||
$prop_id = explode('.', $key);
|
||||
$value = trim($value);
|
||||
|
||||
// if we have requested more levels that exist, set to the max.
|
||||
if ($indexes > count($prop_id)) {
|
||||
$indexes = count($prop_id)-1;
|
||||
}
|
||||
|
||||
for ($i=0;$i<$indexes;$i++) {
|
||||
// Pop the index off.
|
||||
$index = array_pop($prop_id);
|
||||
$value = array($index => $value);
|
||||
}
|
||||
|
||||
// Rebuild our key
|
||||
$key = implode('.',$prop_id);
|
||||
|
||||
// Add the entry to the master array
|
||||
$array = array_replace_recursive($array,array($key => $value));
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user