Rewrite netstats polling (#13368)

* Rewrite netstats polling
As modern module
Don't use snmpgetnext as it can result in extra data returned

* remove copyrights on interfaces

* typehints

* fix silly backslashes
This commit is contained in:
Tony Murray
2021-10-19 19:32:28 -05:00
committed by GitHub
parent c8b394f317
commit fdfea6e93b
17 changed files with 405 additions and 274 deletions

View File

@@ -0,0 +1,8 @@
<?php
namespace LibreNMS\Interfaces\Polling\Netstats;
interface IcmpNetstatsPolling
{
public function pollIcmpNetstats(array $oids): array;
}

View File

@@ -0,0 +1,8 @@
<?php
namespace LibreNMS\Interfaces\Polling\Netstats;
interface IpForwardNetstatsPolling
{
public function pollIpForwardNetstats(array $oids): array;
}

View File

@@ -0,0 +1,8 @@
<?php
namespace LibreNMS\Interfaces\Polling\Netstats;
interface IpNetstatsPolling
{
public function pollIpNetstats(array $oids): array;
}

View File

@@ -0,0 +1,8 @@
<?php
namespace LibreNMS\Interfaces\Polling\Netstats;
interface SnmpNetstatsPolling
{
public function pollSnmpNetstats(array $oids): array;
}

View File

@@ -0,0 +1,8 @@
<?php
namespace LibreNMS\Interfaces\Polling\Netstats;
interface TcpNetstatsPolling
{
public function pollTcpNetstats(array $oids): array;
}

View File

@@ -0,0 +1,8 @@
<?php
namespace LibreNMS\Interfaces\Polling\Netstats;
interface UdpNetstatsPolling
{
public function pollUdpNetstats(array $oids): array;
}

View File

@@ -0,0 +1,223 @@
<?php
/**
* Netstats.php
*
* Poll various netstats. IP, SNMP, ICMP
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* @link https://www.librenms.org
*
* @copyright 2021 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\Modules;
use LibreNMS\Interfaces\Polling\Netstats\IcmpNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\IpForwardNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\IpNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\SnmpNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\TcpNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\UdpNetstatsPolling;
use LibreNMS\OS;
use LibreNMS\RRD\RrdDefinition;
class Netstats implements \LibreNMS\Interfaces\Module
{
/**
* @var string[][]
*/
private $oids = [
'icmp' => [
'IP-MIB::icmpInMsgs.0',
'IP-MIB::icmpOutMsgs.0',
'IP-MIB::icmpInErrors.0',
'IP-MIB::icmpOutErrors.0',
'IP-MIB::icmpInEchos.0',
'IP-MIB::icmpOutEchos.0',
'IP-MIB::icmpInEchoReps.0',
'IP-MIB::icmpOutEchoReps.0',
'IP-MIB::icmpInDestUnreachs.0',
'IP-MIB::icmpOutDestUnreachs.0',
'IP-MIB::icmpInParmProbs.0',
'IP-MIB::icmpInTimeExcds.0',
'IP-MIB::icmpInSrcQuenchs.0',
'IP-MIB::icmpInRedirects.0',
'IP-MIB::icmpInTimestamps.0',
'IP-MIB::icmpInTimestampReps.0',
'IP-MIB::icmpInAddrMasks.0',
'IP-MIB::icmpInAddrMaskReps.0',
'IP-MIB::icmpOutTimeExcds.0',
'IP-MIB::icmpOutParmProbs.0',
'IP-MIB::icmpOutSrcQuenchs.0',
'IP-MIB::icmpOutRedirects.0',
'IP-MIB::icmpOutTimestamps.0',
'IP-MIB::icmpOutTimestampReps.0',
'IP-MIB::icmpOutAddrMasks.0',
'IP-MIB::icmpOutAddrMaskReps.0',
],
'ip' => [
'IP-MIB::ipForwDatagrams.0',
'IP-MIB::ipInDelivers.0',
'IP-MIB::ipInReceives.0',
'IP-MIB::ipOutRequests.0',
'IP-MIB::ipInDiscards.0',
'IP-MIB::ipOutDiscards.0',
'IP-MIB::ipOutNoRoutes.0',
'IP-MIB::ipReasmReqds.0',
'IP-MIB::ipReasmOKs.0',
'IP-MIB::ipReasmFails.0',
'IP-MIB::ipFragOKs.0',
'IP-MIB::ipFragFails.0',
'IP-MIB::ipFragCreates.0',
'IP-MIB::ipInUnknownProtos.0',
'IP-MIB::ipInHdrErrors.0',
'IP-MIB::ipInAddrErrors.0',
],
'ip_forward' => [
'IP-FORWARD-MIB::ipCidrRouteNumber.0',
],
'snmp' => [
'SNMPv2-MIB::snmpInPkts.0',
'SNMPv2-MIB::snmpOutPkts.0',
'SNMPv2-MIB::snmpInBadVersions.0',
'SNMPv2-MIB::snmpInBadCommunityNames.0',
'SNMPv2-MIB::snmpInBadCommunityUses.0',
'SNMPv2-MIB::snmpInASNParseErrs.0',
'SNMPv2-MIB::snmpInTooBigs.0',
'SNMPv2-MIB::snmpInNoSuchNames.0',
'SNMPv2-MIB::snmpInBadValues.0',
'SNMPv2-MIB::snmpInReadOnlys.0',
'SNMPv2-MIB::snmpInGenErrs.0',
'SNMPv2-MIB::snmpInTotalReqVars.0',
'SNMPv2-MIB::snmpInTotalSetVars.0',
'SNMPv2-MIB::snmpInGetRequests.0',
'SNMPv2-MIB::snmpInGetNexts.0',
'SNMPv2-MIB::snmpInSetRequests.0',
'SNMPv2-MIB::snmpInGetResponses.0',
'SNMPv2-MIB::snmpInTraps.0',
'SNMPv2-MIB::snmpOutTooBigs.0',
'SNMPv2-MIB::snmpOutNoSuchNames.0',
'SNMPv2-MIB::snmpOutBadValues.0',
'SNMPv2-MIB::snmpOutGenErrs.0',
'SNMPv2-MIB::snmpOutGetRequests.0',
'SNMPv2-MIB::snmpOutGetNexts.0',
'SNMPv2-MIB::snmpOutSetRequests.0',
'SNMPv2-MIB::snmpOutGetResponses.0',
'SNMPv2-MIB::snmpOutTraps.0',
'SNMPv2-MIB::snmpSilentDrops.0',
'SNMPv2-MIB::snmpProxyDrops.0',
],
'tcp' => [
'TCP-MIB::tcpActiveOpens.0',
'TCP-MIB::tcpPassiveOpens.0',
'TCP-MIB::tcpAttemptFails.0',
'TCP-MIB::tcpEstabResets.0',
'TCP-MIB::tcpCurrEstab.0',
'TCP-MIB::tcpInSegs.0',
'TCP-MIB::tcpOutSegs.0',
'TCP-MIB::tcpRetransSegs.0',
'TCP-MIB::tcpInErrs.0',
'TCP-MIB::tcpOutRsts.0',
],
'udp' => [
'UDP-MIB::udpInDatagrams.0',
'UDP-MIB::udpOutDatagrams.0',
'UDP-MIB::udpInErrors.0',
'UDP-MIB::udpNoPorts.0',
],
];
/**
* @var string[][]
*/
private $graphs = [
'icmp' => ['netstat_icmp', 'netstat_icmp_info'],
'ip' => ['netstat_ip', 'netstat_ip_frag'],
'ip_forward' => ['netstat_ip_forward'],
'snmp' => ['netstat_snmp', 'netstat_snmp_pkt'],
'tcp' => ['netstat_tcp'],
'udp' => ['netstat_udp'],
];
/**
* @var string[]
*/
private $types = [
'icmp' => IcmpNetstatsPolling::class,
'ip' => IpNetstatsPolling::class,
'ip_forward' => IpForwardNetstatsPolling::class,
'snmp' => SnmpNetstatsPolling::class,
'udp' => UdpNetstatsPolling::class,
'tcp' => TcpNetstatsPolling::class,
];
/**
* @inheritDoc
*/
public function discover(OS $os): void
{
// no discovery
}
/**
* @inheritDoc
*/
public function poll(OS $os): void
{
foreach ($this->types as $type => $interface) {
if ($os instanceof $interface) {
echo "$type ";
$method = (new \ReflectionClass($interface))->getMethods()[0]->getName();
$data = $os->$method($this->oids[$type]);
// we have data, update it
if (! empty($data)) {
$rrd_def = new RrdDefinition();
$fields = [];
foreach ($this->oids[$type] as $oid) {
$stat = $this->statName($oid);
$rrd_def->addDataset($stat, 'COUNTER', null, 100000000000);
$fields[$stat] = $data[$oid] ?? null;
}
app('Datastore')->put($os->getDeviceArray(), "netstats-$type", ['rrd_def' => $rrd_def], $fields);
// enable graphs
foreach ($this->graphs[$type] as $graph) {
$os->enableGraph($graph);
}
}
}
}
echo PHP_EOL;
}
/**
* @inheritDoc
*/
public function cleanup(OS $os): void
{
// no cleanup
}
private function statName(string $oid): string
{
$start = strpos($oid, '::') + 2;
$length = min(strpos($oid, '.') - $start, 19); // 19 is max RRD ds length
return substr($oid, $start, $length);
}
}

View File

@@ -34,14 +34,30 @@ use LibreNMS\Device\YamlDiscovery;
use LibreNMS\Interfaces\Discovery\MempoolsDiscovery;
use LibreNMS\Interfaces\Discovery\OSDiscovery;
use LibreNMS\Interfaces\Discovery\ProcessorDiscovery;
use LibreNMS\Interfaces\Polling\Netstats\IcmpNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\IpForwardNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\IpNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\SnmpNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\TcpNetstatsPolling;
use LibreNMS\Interfaces\Polling\Netstats\UdpNetstatsPolling;
use LibreNMS\OS\Generic;
use LibreNMS\OS\Traits\HostResources;
use LibreNMS\OS\Traits\NetstatsPolling;
use LibreNMS\OS\Traits\UcdResources;
use LibreNMS\OS\Traits\YamlMempoolsDiscovery;
use LibreNMS\OS\Traits\YamlOSDiscovery;
use LibreNMS\Util\StringHelpers;
class OS implements ProcessorDiscovery, OSDiscovery, MempoolsDiscovery
class OS implements
ProcessorDiscovery,
OSDiscovery,
MempoolsDiscovery,
IcmpNetstatsPolling,
IpNetstatsPolling,
IpForwardNetstatsPolling,
SnmpNetstatsPolling,
TcpNetstatsPolling,
UdpNetstatsPolling
{
use HostResources {
HostResources::discoverProcessors as discoverHrProcessors;
@@ -53,6 +69,7 @@ class OS implements ProcessorDiscovery, OSDiscovery, MempoolsDiscovery
}
use YamlOSDiscovery;
use YamlMempoolsDiscovery;
use NetstatsPolling;
private $device; // annoying use of references to make sure this is in sync with global $device variable
private $graphs; // stores device graphs

50
LibreNMS/OS/Asa.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
/**
* Asa.php
*
* -Description-
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* @link https://www.librenms.org
*
* @copyright 2021 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\OS;
class Asa extends Shared\Cisco
{
// disable unsupported netstats
public function pollIcmpNetstats(array $oids): array
{
return [];
}
public function pollIpNetstats(array $oids): array
{
return [];
}
public function pollUdpNetstats(array $oids): array
{
return [];
}
public function pollTcpNetstats(array $oids): array
{
return [];
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* NetstatsPolling.php
*
* -Description-
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* @link https://www.librenms.org
*
* @copyright 2021 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\OS\Traits;
use SnmpQuery;
trait NetstatsPolling
{
public function pollIcmpNetstats(array $oids): array
{
return SnmpQuery::get($oids)->values();
}
public function pollIpNetstats(array $oids): array
{
return SnmpQuery::get($oids)->values();
}
public function pollSnmpNetstats(array $oids): array
{
return SnmpQuery::get($oids)->values();
}
public function pollIpForwardNetstats(array $oids): array
{
return SnmpQuery::get($oids)->values();
}
public function pollUdpNetstats(array $oids): array
{
return SnmpQuery::get($oids)->values();
}
public function pollTcpNetstats(array $oids): array
{
return SnmpQuery::get($oids)->values();
}
}

View File

@@ -1,7 +1,8 @@
<?php
$include_dir = 'includes/polling/netstats';
require 'includes/include-dir.inc.php';
use LibreNMS\OS;
echo "\n";
unset($oid_ds);
if (! $os instanceof OS) {
$os = OS::make($device);
}
(new \LibreNMS\Modules\Netstats())->poll($os);

View File

@@ -1,58 +0,0 @@
<?php
use Illuminate\Support\Str;
use LibreNMS\RRD\RrdDefinition;
if (! Str::startsWith($device['os'], ['Snom', 'asa'])) {
echo ' ICMP';
// Below have more oids, and are in trees by themselves, so we can snmpwalk_cache_oid them
$oids = [
'icmpInMsgs',
'icmpOutMsgs',
'icmpInErrors',
'icmpOutErrors',
'icmpInEchos',
'icmpOutEchos',
'icmpInEchoReps',
'icmpOutEchoReps',
'icmpInDestUnreachs',
'icmpOutDestUnreachs',
'icmpInParmProbs',
'icmpInTimeExcds',
'icmpInSrcQuenchs',
'icmpInRedirects',
'icmpInTimestamps',
'icmpInTimestampReps',
'icmpInAddrMasks',
'icmpInAddrMaskReps',
'icmpOutTimeExcds',
'icmpOutParmProbs',
'icmpOutSrcQuenchs',
'icmpOutRedirects',
'icmpOutTimestamps',
'icmpOutTimestampReps',
'icmpOutAddrMasks',
'icmpOutAddrMaskReps',
];
$data = snmpwalk_cache_oid($device, 'icmp', [], 'IP-MIB');
$data = $data[0];
if (isset($data['icmpInMsgs']) && isset($data['icmpOutMsgs'])) {
$rrd_def = new RrdDefinition();
$fields = [];
foreach ($oids as $oid) {
$rrd_def->addDataset($oid, 'COUNTER', null, 100000000000);
$fields[substr($oid, 0, 19)] = isset($data[$oid]) ? $data[$oid] : 'U';
}
$tags = compact('rrd_def');
data_update($device, 'netstats-icmp', $tags, $fields);
$os->enableGraph('netstat_icmp');
$os->enableGraph('netstat_icmp_info');
}
unset($oids, $data, $rrd_def, $fields, $tags);
}//end if

View File

@@ -1,47 +0,0 @@
<?php
use Illuminate\Support\Str;
use LibreNMS\RRD\RrdDefinition;
if (! Str::startsWith($device['os'], ['Snom', 'asa'])) {
echo ' IP';
$oids = [
'ipForwDatagrams',
'ipInDelivers',
'ipInReceives',
'ipOutRequests',
'ipInDiscards',
'ipOutDiscards',
'ipOutNoRoutes',
'ipReasmReqds',
'ipReasmOKs',
'ipReasmFails',
'ipFragOKs',
'ipFragFails',
'ipFragCreates',
'ipInUnknownProtos',
'ipInHdrErrors',
'ipInAddrErrors',
];
$data = snmp_getnext_multi($device, $oids, '-OQUs', 'IP-MIB');
if (is_numeric($data['ipOutRequests']) && is_numeric($data['ipInReceives'])) {
$rrd_def = new RrdDefinition();
$fields = [];
foreach ($oids as $oid) {
$rrd_def->addDataset($oid, 'COUNTER', null, 100000000000);
$fields[$oid] = is_numeric($data[$oid]) ? $data[$oid] : 'U';
}
$tags = compact('rrd_def');
data_update($device, 'netstats-ip', $tags, $fields);
$os->enableGraph('netstat_ip');
$os->enableGraph('netstat_ip_frag');
unset($rrd_def, $fields, $tags, $oid);
}
unset($oids, $data);
}//end if

View File

@@ -1,21 +0,0 @@
<?php
use Illuminate\Support\Str;
use LibreNMS\RRD\RrdDefinition;
if (! Str::startsWith($device['os'], ['Snom', 'asa'])) {
echo ' IP-FORWARD';
$oid = 'ipCidrRouteNumber';
$fields = [];
$rrd_def = RrdDefinition::make()->addDataset($oid, 'GAUGE', null, 5000000);
$data = snmp_get($device, 'IP-FORWARD-MIB::' . $oid . '.0', '-OQv');
if (is_numeric($data)) {
$value = $data;
$fields[$oid] = $value;
$tags = compact('rrd_def');
data_update($device, 'netstats-ip_forward', $tags, $fields);
$os->enableGraph('netstat_ip_forward');
}
}
unset($oid, $rrd_def, $data, $fields, $tags);

View File

@@ -1,59 +0,0 @@
<?php
use LibreNMS\RRD\RrdDefinition;
if ($device['os'] != 'Snom') {
echo ' SNMP';
// Below have more oids, and are in trees by themselves, so we can snmpwalk_cache_oid them
$oids = [
'snmpInPkts',
'snmpOutPkts',
'snmpInBadVersions',
'snmpInBadCommunityNames',
'snmpInBadCommunityUses',
'snmpInASNParseErrs',
'snmpInTooBigs',
'snmpInNoSuchNames',
'snmpInBadValues',
'snmpInReadOnlys',
'snmpInGenErrs',
'snmpInTotalReqVars',
'snmpInTotalSetVars',
'snmpInGetRequests',
'snmpInGetNexts',
'snmpInSetRequests',
'snmpInGetResponses',
'snmpInTraps',
'snmpOutTooBigs',
'snmpOutNoSuchNames',
'snmpOutBadValues',
'snmpOutGenErrs',
'snmpOutGetRequests',
'snmpOutGetNexts',
'snmpOutSetRequests',
'snmpOutGetResponses',
'snmpOutTraps',
'snmpSilentDrops',
'snmpProxyDrops',
];
$data = snmpwalk_cache_oid($device, 'snmp', [], 'SNMPv2-MIB');
if (isset($data[0]['snmpInPkts'])) {
$rrd_def = new RrdDefinition();
$fields = [];
foreach ($oids as $oid) {
$rrd_def->addDataset($oid, 'COUNTER', null, 100000000000);
$fields[substr($oid, 0, 19)] = isset($data[0][$oid]) ? $data[0][$oid] : 'U';
}
$tags = compact('rrd_def');
data_update($device, 'netstats-snmp', $tags, $fields);
$os->enableGraph('netstat_snmp');
$os->enableGraph('netstat_snmp_pkt');
}
unset($oids, $data, $rrd_def, $fields, $tags);
}//end if

View File

@@ -1,50 +0,0 @@
<?php
use Illuminate\Support\Str;
use LibreNMS\RRD\RrdDefinition;
if (! Str::startsWith($device['os'], ['Snom', 'asa'])) {
echo ' TCP';
$oids = [
'tcpActiveOpens',
'tcpPassiveOpens',
'tcpAttemptFails',
'tcpEstabResets',
'tcpCurrEstab',
'tcpInSegs',
'tcpOutSegs',
'tcpRetransSegs',
'tcpInErrs',
'tcpOutRsts',
];
$data = snmp_getnext_multi($device, $oids, '-OQUs', 'TCP-MIB');
echo ' TCPHC';
$hc_oids = [
'tcpHCInSegs.0',
'tcpHCOutSegs.0',
];
$hc_data = snmp_getnext_multi($device, $hc_oids, '-OQUs', 'TCP-MIB');
if ((is_numeric($data['tcpInSegs']) && is_numeric($data['tcpOutSegs'])) || (is_numeric($hc_data['tcpHCInSegs']) && is_numeric($hc_data['tcpHCOutSegs']))) {
$rrd_def = new RrdDefinition();
$fields = [];
foreach ($oids as $oid) {
$rrd_def->addDataset($oid, 'COUNTER', null, 10000000);
$fields[$oid] = is_numeric($data[$oid]) ? $data[$oid] : 'U';
}
// Replace Segs with HC Segs if we have them.
$fields['tcpInSegs'] = ! empty($hc_data['tcpHCInSegs']) ? $hc_data['tcpHCInSegs'] : $fields['tcpInSegs'];
$fields['tcpOutSegs'] = ! empty($hc_data['tcpHCOutSegs']) ? $hc_data['tcpHCOutSegs'] : $fields['tcpOutSegs'];
$tags = compact('rrd_def');
data_update($device, 'netstats-tcp', $tags, $fields);
$os->enableGraph('netstat_tcp');
unset($rrd_def, $fields, $tags, $oid);
}
unset($oids, $hc_oids, $data, $hc_data);
}//end if

View File

@@ -1,34 +0,0 @@
<?php
use Illuminate\Support\Str;
use LibreNMS\RRD\RrdDefinition;
if (! Str::startsWith($device['os'], ['Snom', 'asa'])) {
echo ' UDP';
$oids = [
'udpInDatagrams',
'udpOutDatagrams',
'udpInErrors',
'udpNoPorts',
];
$data = snmp_getnext_multi($device, $oids, '-OQUs', 'UDP-MIB');
if (is_numeric($data['udpInDatagrams']) && is_numeric($data['udpOutDatagrams'])) {
$rrd_def = new RrdDefinition();
$fields = [];
foreach ($oids as $oid) {
$rrd_def->addDataset($oid, 'COUNTER', null, 1000000); // Limit to 1MPPS?
$fields[$oid] = is_numeric($data[$oid]) ? $data[$oid] : 'U';
}
$tags = compact('rrd_def');
data_update($device, 'netstats-udp', $tags, $fields);
$os->enableGraph('netstat_udp');
unset($rrd_def, $fields, $tags, $oid);
}
unset($oids, $data);
}//end if