librenms/includes/discovery/stp.inc.php
Tony Murray eeb3d58f5b Improved Logging and Debugging (#8870)
Use Log facility when Laravel is booted.
Update init.php so we can easily boot Laravel for CLI scripts. (and just Eloquent, but that may go away)
Move all debug setup into set_debug() function and use that across all scripts.
Log Laravel database queries.
Send debug output to librenms log file when enabling debug in the webui.
Allow for colorized Log CLI output. (currently will leave % tags in log file output)

** Needs testing and perhaps tweaking still.

DO NOT DELETE THIS TEXT

#### Please note

> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting.

- [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/)

#### Testers

If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926`
2018-07-13 23:08:00 +01:00

177 lines
7.7 KiB
PHP

<?php
/*
* LibreNMS
*
* Copyright (c) 2015 Vitali Kari <vitali.kari@gmail.com>
*
* 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.
*
* Based on IEEE-802.1D-2004, (STP, RSTP)
* needs RSTP-MIB
*/
// Pre-cache existing state of STP for this device from database
$stp_db = dbFetchRow('SELECT * FROM `stp` WHERE `device_id` = ?', array($device['device_id']));
//d_echo($stp_db);
$stpprotocol = snmp_get($device, 'dot1dStpProtocolSpecification.0', '-Oqv', 'RSTP-MIB');
// FIXME I don't know what "unknown" means, perhaps MSTP? (saw it on some cisco devices)
// But we can try to retrieve data
if ($stpprotocol == 'ieee8021d' || $stpprotocol == 'unknown') {
// set time multiplier to convert from centiseconds to seconds
// all time values are stored in databese as seconds
$tm = '0.01';
// some vendors like PBN dont follow the 802.1D implementation and use seconds in SNMP
if ($device['os'] == 'pbn') {
preg_match('/^.* Build (?<build>\d+)/', $device['version'], $version);
if ($version['build'] <= 16607) { // Buggy version :-(
$tm = '1';
}
}
// read the 802.1D subtree
$stp_raw = snmpwalk_cache_oid($device, 'dot1dStp', array(), 'RSTP-MIB');
$stp = array(
'protocolSpecification' => $stp_raw[0]['dot1dStpProtocolSpecification'],
'priority' => $stp_raw[0]['dot1dStpPriority'],
'topChanges' => $stp_raw[0]['dot1dStpTopChanges'],
'rootCost' => $stp_raw[0]['dot1dStpRootCost'],
'rootPort' => $stp_raw[0]['dot1dStpRootPort'],
'maxAge' => $stp_raw[0]['dot1dStpMaxAge'] * $tm,
'helloTime' => $stp_raw[0]['dot1dStpHelloTime'] * $tm,
'holdTime' => $stp_raw[0]['dot1dStpHoldTime'] * $tm,
'forwardDelay' => $stp_raw[0]['dot1dStpForwardDelay'] * $tm,
'bridgeMaxAge' => $stp_raw[0]['dot1dStpBridgeMaxAge'] * $tm,
'bridgeHelloTime' => $stp_raw[0]['dot1dStpBridgeHelloTime'] * $tm,
'bridgeForwardDelay' => $stp_raw[0]['dot1dStpBridgeForwardDelay'] * $tm
);
// set device binding
$stp['device_id'] = $device['device_id'];
// read the 802.1D bridge address and set as MAC in database
$mac_raw = snmp_get($device, 'dot1dBaseBridgeAddress.0', '-Oqv', 'RSTP-MIB');
// read Time as timetics (in hundredths of a seconds) since last topology change and convert to seconds
$time_since_change = snmp_get($device, 'dot1dStpTimeSinceTopologyChange.0', '-Ovt', 'RSTP-MIB');
if ($time_since_change > '100') {
$time_since_change = substr($time_since_change, 0, -2); // convert to seconds since change
} else {
$time_since_change = '0';
}
$stp['timeSinceTopologyChange'] = $time_since_change;
// designated root is stored in format 2 octet bridge priority + MAC address, so we need to normalize it
$dr = str_replace(array(' ', ':', '-'), '', strtolower($stp_raw[0]['dot1dStpDesignatedRoot']));
$dr = substr($dr, -12); //remove first two octets
$stp['designatedRoot'] = $dr;
// normalize the MAC
$mac_array = explode(':', $mac_raw);
foreach ($mac_array as &$octet) {
if (strlen($octet) < 2) {
$octet = "0" . $octet; // add suppressed 0
}
}
$stp['bridgeAddress'] = implode($mac_array);
// I'm the boss?
if ($stp['bridgeAddress'] == $stp['designatedRoot']) {
$stp['rootBridge'] = '1';
} else {
$stp['rootBridge'] = '0';
}
d_echo($stp);
if ($stp_raw[0]['version'] == '3') {
echo "RSTP ";
} else {
echo "STP ";
}
if (!$stp_db['bridgeAddress'] && $stp['bridgeAddress']) {
dbInsert($stp, 'stp');
log_event('STP added, bridge address: ' . $stp['bridgeAddress'], $device, 'stp', 3);
echo '+';
}
if ($stp_db['bridgeAddress'] && !$stp['bridgeAddress']) {
dbDelete('stp', 'device_id = ?', array($device['device_id']));
log_event('STP removed', $device, 'stp', 4);
echo '-';
}
// STP port related stuff
foreach ($stp_raw as $port => $value) {
if ($port) { // $stp_raw[0] ist not port related so we skip this one
$stp_port = array(
'priority' => $stp_raw[$port]['dot1dStpPortPriority'],
'state' => $stp_raw[$port]['dot1dStpPortState'],
'enable' => $stp_raw[$port]['dot1dStpPortEnable'],
'pathCost' => $stp_raw[$port]['dot1dStpPortPathCost'],
'designatedCost' => $stp_raw[$port]['dot1dStpPortDesignatedCost'],
'designatedPort' => $stp_raw[$port]['dot1dStpPortDesignatedPort'],
'forwardTransitions' => $stp_raw[$port]['dot1dStpPortForwardTransitions']
);
// set device binding
$stp_port['device_id'] = $device['device_id'];
// set port binding
$stp_port['port_id'] = dbFetchCell('SELECT port_id FROM `ports` WHERE `device_id` = ? AND `ifIndex` = ?', array($device['device_id'], $stp_raw[$port]['dot1dStpPort']));
$dr = str_replace(array(' ', ':', '-'), '', strtolower($stp_raw[$port]['dot1dStpPortDesignatedRoot']));
$dr = substr($dr, -12); //remove first two octets
$stp_port['designatedRoot'] = $dr;
$db = str_replace(array(' ', ':', '-'), '', strtolower($stp_raw[$port]['dot1dStpPortDesignatedBridge']));
$db = substr($db, -12); //remove first two octets
$stp_port['designatedBridge'] = $db;
if ($device['os'] == 'pbn') {
// It seems that PBN guys don't care about ieee 802.1d :-(
// So try to find the right port with some crazy conversations
$dp_value = dechex($stp_port['priority']);
$dp_value = $dp_value.'00';
$dp_value = hexdec($dp_value);
if ($stp_raw[$port]['dot1dStpPortDesignatedPort']) {
$dp = $stp_raw[$port]['dot1dStpPortDesignatedPort'] - $dp_value;
$stp_port['designatedPort'] = $dp;
}
} else {
// Port saved in format priority+port (ieee 802.1d-1998: clause 8.5.5.1)
$dp = substr($stp_raw[$port]['dot1dStpPortDesignatedPort'], -2); //discard the first octet (priority part)
$stp_port['designatedPort'] = hexdec($dp);
}
d_echo($stp_port);
// Write to db
if (!dbFetchCell('SELECT 1 FROM `ports_stp` WHERE `device_id` = ? AND `port_id` = ?', array($device['device_id'], $stp_port['port_id']))) {
dbInsert($stp_port, 'ports_stp');
echo '+';
}
}
}
// Delete STP ports from db if absent in SNMP query
$stp_port_db = dbFetchRows('SELECT * FROM `ports_stp` WHERE `device_id` = ?', array($device['device_id']));
//d_echo($stp_port_db);
foreach ($stp_port_db as $port => $value) {
$if_index = dbFetchCell('SELECT `ifIndex` FROM `ports` WHERE `device_id` = ? AND `port_id` = ?', array($device['device_id'], $value['port_id']));
if ($if_index != $stp_raw[$if_index]['dot1dStpPort']) {
dbDelete('ports_stp', '`device_id` = ? AND `port_id` = ?', array($device['device_id'], $value['port_id']));
echo '-';
}
}
}
unset($stp_raw, $stp, $stp_db, $stp_port, $stp_port_db);
echo "\n";