From b891b6f4f240fee5ada683fb2387a6ccba3a28e4 Mon Sep 17 00:00:00 2001 From: Adam Amstrong Date: Fri, 11 May 2012 18:08:48 +0000 Subject: [PATCH] ports poller update (fix not adding filtered interfaces) git-svn-id: http://www.observium.org/svn/observer/trunk@3173 61d68cd4-352d-0410-923a-c4978735b2b8 --- includes/discovery/ports.inc.php | 436 ++++++++++++++++++++++++++++++- 1 file changed, 425 insertions(+), 11 deletions(-) diff --git a/includes/discovery/ports.inc.php b/includes/discovery/ports.inc.php index 6d3300c99c..ee93e2bc2c 100755 --- a/includes/discovery/ports.inc.php +++ b/includes/discovery/ports.inc.php @@ -1,23 +1,135 @@ "0") +{ + echo("ADSL "); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.1.1", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.2.1", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.3.1", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.4.1", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.5.1", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.6.1.1", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.6.1.2", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.6.1.3", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.6.1.4", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.6.1.5", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.6.1.6", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.6.1.7", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.6.1.8", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.7.1.1", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.7.1.2", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.7.1.3", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.7.1.4", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.7.1.5", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.7.1.6", $port_stats, "ADSL-LINE-MIB"); + $port_stats = snmpwalk_cache_oid($device, ".1.3.6.1.2.1.10.94.1.1.7.1.7", $port_stats, "ADSL-LINE-MIB"); +} + +/// FIXME This probably needs re-enabled. We need to clear these things when they get unset, too. +#foreach ($etherlike_oids as $oid) { $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "EtherLike-MIB"); } +#foreach ($cisco_oids as $oid) { $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "OLD-CISCO-INTERFACES-MIB"); } +#foreach ($pagp_oids as $oid) { $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "CISCO-PAGP-MIB"); } + +if ($device['os_group'] == "cisco") +{ + $port_stats = snmp_cache_portIfIndex ($device, $port_stats); + $port_stats = snmp_cache_portName ($device, $port_stats); + foreach ($pagp_oids as $oid) { $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "CISCO-PAGP-MIB"); } + $data_oids[] = "portName"; + + /// Grab data to put ports into vlans or make them trunks + /// FIXME we probably shouldn't be doing this from the VTP MIB, right? + $port_stats = snmpwalk_cache_oid($device, "vmVlan", $port_stats, "CISCO-VLAN-MEMBERSHIP-MIB"); + $port_stats = snmpwalk_cache_oid($device, "vlanTrunkPortEncapsulationOperType", $port_stats, "CISCO-VTP-MIB"); + $port_stats = snmpwalk_cache_oid($device, "vlanTrunkPortNativeVlan", $port_stats, "CISCO-VTP-MIB"); + +} else { + $port_stats = snmpwalk_cache_oid($device, "dot1qPortVlanTable", $port_stats, "Q-BRIDGE-MIB"); + + $vlan_ports = snmpwalk_cache_twopart_oid($device, "dot1qVlanCurrentEgressPorts", $vlan_stats, "Q-BRIDGE-MIB"); + $vlan_ifindex_map = snmpwalk_cache_oid($device, "dot1dBasePortIfIndex", $vlan_stats, "Q-BRIDGE-MIB"); + + foreach ($vlan_ports as $instance) + { + foreach (array_keys($instance) as $vlan_id) + { + $parts = explode(' ',$instance[$vlan_id]['dot1qVlanCurrentEgressPorts']); + $binary = ''; + foreach ($parts as $part) + { + $binary .= zeropad(decbin($part),8); + } + for ($i = 0; $i < strlen($binary); $i++) + { + if ($binary[$i]) + { + $ifindex = $i; // FIXME $vlan_ifindex_map[$i] + $q_bridge_mib[$ifindex][] = $vlan_id; + } + } + } + } +} + +$polled = time(); + +/// End Building SNMP Cache Array + +if ($debug) { print_r($port_stats); } + +/// Build array of ports in the database + +## FIXME -- this stuff is a little messy, looping the array to make an array just seems wrong. :> +## -- i can make it a function, so that you don't know what it's doing. +## -- $ports_db = adamasMagicFunction($ports_db); ? -/// Loop database and build a little cache to reduce db hits. foreach(dbFetchRows("SELECT * FROM `ports` WHERE `device_id` = ?", array($device['device_id'])) as $port) { $ports_db[$port['ifIndex']] = $port; - $ports_l[$port['ifIndex']] = $port['interface_id']; + $ports_db_l[$port['ifIndex']] = $port['interface_id']; } -#print_r($ports_db); - -$port_stats = array(); -$port_stats = snmpwalk_cache_oid($device, "ifDescr", $port_stats, "IF-MIB"); -$port_stats = snmpwalk_cache_oid($device, "ifName", $port_stats, "IF-MIB"); -$port_stats = snmpwalk_cache_oid($device, "ifType", $port_stats, "IF-MIB"); - /// New interface detection foreach ($port_stats as $ifIndex => $port) { @@ -27,6 +139,7 @@ foreach ($port_stats as $ifIndex => $port) if (!is_array($ports_db[$ifIndex])) { $interface_id = dbInsert(array('device_id' => $device['device_id'], 'ifIndex' => $ifIndex), 'ports'); + $ports_db[$ifIndex] = dbFetchRow("SELECT * FROM `ports` WHERE `device_id` = ? AND `ifIndex` = ?", array($device['device_id'], $ifIndex)); echo("Adding: ".$port['ifName']."(".$ifIndex.")(".$ports_db[$port['ifIndex']]['interface_id'].")"); } elseif ($ports_db[$ifIndex]['deleted'] == "1") { dbUpdate(array('deleted' => '0'), 'ports', '`interface_id` = ?', array($ports_db[$ifIndex]['interface_id'])); @@ -64,5 +177,306 @@ foreach($ports_l as $ifIndex => $port_id) /// End interface deletion echo("\n"); +/// Loop ports in the DB and update where necessary +foreach ($ports_db as $port) +{ + echo("Port " . $port['ifDescr'] . "(".$port['ifIndex'].") "); + if ($port_stats[$port['ifIndex']] && $port['disabled'] != "1") + { /// Check to make sure Port data is cached. + $this_port = &$port_stats[$port['ifIndex']]; + + if ($device['os'] == "vmware" && preg_match("/Device ([a-z0-9]+) at .*/", $this_port['ifDescr'], $matches)) { $this_port['ifDescr'] = $matches[1]; } + + if ($config['memcached']['enable']) + { + $port['poll_time'] = $memcache->get('port-'.$port['interface_id'].'-poll_time'); +# echo("time".$port['poll_time']); + } + + $polled_period = $polled - $port['poll_time']; + + $port['update'] = array(); + if ($config['slow_statistics'] == TRUE) + { + $port['update']['poll_time'] = $polled; + $port['update']['poll_prev'] = $port['poll_time']; + $port['update']['poll_period'] = $polled_period; + } + + if ($config['memcached']['enable']) + { + $memcache->set('port-'.$port['interface_id'].'-poll_time', $polled); + $memcache->set('port-'.$port['interface_id'].'-poll_prev', $port['poll_time']); + $memcache->set('port-'.$port['interface_id'].'-poll_period', $polled_period); + } + + /// Copy ifHC[In|Out]Octets values to non-HC if they exist + if ($this_port['ifHCInOctets'] > 0 && is_numeric($this_port['ifHCInOctets']) && $this_port['ifHCOutOctets'] > 0 && is_numeric($this_port['ifHCOutOctets'])) + { + echo("HC "); + $this_port['ifInOctets'] = $this_port['ifHCInOctets']; + $this_port['ifOutOctets'] = $this_port['ifHCOutOctets']; + } + + /// rewrite the ifPhysAddress + if (strpos($this_port['ifPhysAddress'], ":")) + { + list($a_a, $a_b, $a_c, $a_d, $a_e, $a_f) = explode(":", $this_port['ifPhysAddress']); + $this_port['ifPhysAddress'] = zeropad($a_a).zeropad($a_b).zeropad($a_c).zeropad($a_d).zeropad($a_e).zeropad($a_f); + } + + if (is_numeric($this_port['ifHCInBroadcastPkts']) && is_numeric($this_port['ifHCOutBroadcastPkts']) && is_numeric($this_port['ifHCInMulticastPkts']) && is_numeric($this_port['ifHCOutMulticastPkts'])) + { + echo("HC "); + $this_port['ifInBroadcastPkts'] = $this_port['ifHCInBroadcastPkts']; + $this_port['ifOutBroadcastPkts'] = $this_port['ifHCOutBroadcastPkts']; + $this_port['ifInMulticastPkts'] = $this_port['ifHCInMulticastPkts']; + $this_port['ifOutMulticastPkts'] = $this_port['ifHCOutMulticastPkts']; + } + + /// Overwrite ifSpeed with ifHighSpeed if it's over 10G + if (is_numeric($this_port['ifHighSpeed']) && $this_port['ifSpeed'] > "1000000000") + { + echo("HighSpeed "); + $this_port['ifSpeed'] = $this_port['ifHighSpeed'] * 1000000; + } + + /// Overwrite ifDuplex with dot3StatsDuplexStatus if it exists + if (isset($this_port['dot3StatsDuplexStatus'])) + { + echo("dot3Duplex "); + $this_port['ifDuplex'] = $this_port['dot3StatsDuplexStatus']; + } + + /// Set VLAN and Trunk from Cisco + if (isset($this_port['vlanTrunkPortEncapsulationOperType']) && $this_port['vlanTrunkPortEncapsulationOperType'] != "notApplicable") + { + $this_port['ifTrunk'] = $this_port['vlanTrunkPortEncapsulationOperType']; + if (isset($this_port['vlanTrunkPortNativeVlan'])) { $this_port['ifVlan'] = $this_port['vlanTrunkPortNativeVlan']; } + } + + if (isset($this_port['vmVlan'])) + { + $this_port['ifVlan'] = $this_port['vmVlan']; + } + + /// Set VLAN and Trunk from Q-BRIDGE-MIB + if (!isset($this_port['ifVlan']) && isset($this_port['dot1qPvid'])) + { + $this_port['ifVlan'] = $this_port['dot1qPvid']; + } + # FIXME use $q_bridge_mib[$this_port['ifIndex'] to see if it is a trunk (>1 array count) + + echo("VLAN == ".$this_port['ifVlan']); + + /// Update IF-MIB data + foreach ($data_oids as $oid) + { + if ($port[$oid] != $this_port[$oid] && !isset($this_port[$oid])) + { + $port['update'][$oid] = NULL; + log_event($oid . ": ".$port[$oid]." -> NULL", $device, 'interface', $port['interface_id']); + if ($debug) { echo($oid . ": ".$port[$oid]." -> NULL "); } else { echo($oid . " "); } + } elseif ($port[$oid] != $this_port[$oid]) { + $port['update'][$oid] = $this_port[$oid]; + log_event($oid . ": ".$port[$oid]." -> " . $this_port[$oid], $device, 'interface', $port['interface_id']); + if ($debug) { echo($oid . ": ".$port[$oid]." -> " . $this_port[$oid]." "); } else { echo($oid . " "); } + } + } + + /// Parse description (usually ifAlias) if config option set + if (isset($config['port_descr_parser']) && is_file($config['install_dir'] . "/" . $config['port_descr_parser'])) + { + $port_attribs = array('type','descr','circuit','speed','notes'); + + include($config['install_dir'] . "/" . $config['port_descr_parser']); + + foreach ($port_attribs as $attrib) + { + $attrib_key = "port_descr_".$attrib; + if ($port_ifAlias[$attrib] != $port[$attrib_key]) + { + $port['update'][$attrib_key] = $port_ifAlias[$attrib]; + log_event($attrib . ": ".$port[$attrib_key]." -> " . $port_ifAlias[$attrib], $device, 'interface', $port['interface_id']); + } + } + } + /// End parse ifAlias + + /// Update IF-MIB metrics + foreach ($stat_oids_db as $oid) + { +# echo("\n".$oid.":"); + + if ($config['slow_statistics'] == TRUE) { + $port['update'][$oid] = $this_port[$oid]; + $port['update'][$oid.'_prev'] = $port[$oid]; + } + + if ($config['memcached']['enable']) + { + $port[$oid] = $memcache->get('port-'.$port['interface_id'].'-'.$oid); + $memcache->set('port-'.$port['interface_id'].'-'.$oid, $this_port[$oid]); + $memcache->set('port-'.$port['interface_id'].'-'.$oid.'_prev', $port[$oid]); +# echo("MEMCACHE!"); + } + +# echo(" old[".$port[$oid]."]"); +# echo(" new[".$this_port[$oid]."]"); + + $oid_prev = $oid . "_prev"; + if (isset($port[$oid])) + { + $oid_diff = $this_port[$oid] - $port[$oid]; +# echo(" diff[".$oid_diff."]"); + $oid_rate = $oid_diff / $polled_period; +# echo(" rate[".$oid_rate."]"); + if ($oid_rate < 0) { $oid_rate = "0"; echo("negative $oid"); } + $port['stats'][$oid.'_rate'] = $oid_rate; + $port['stats'][$oid.'_diff'] = $oid_diff; + + if ($config['slow_statistics'] == TRUE) { + $port['update'][$oid.'_rate'] = $oid_rate; + $port['update'][$oid.'_delta'] = $oid_diff; + } + + if ($config['memcached']['enable']) + { + $memcache->set('port-'.$port['interface_id'].'-'.$oid.'_rate', $oid_rate); + $memcache->set('port-'.$port['interface_id'].'-'.$oid.'_delta', $oid_diff); +# echo($oid."[".$oid_rate."]"); + } + + if ($debug) { echo("\n $oid ($oid_diff B) $oid_rate Bps $polled_period secs\n"); } + } + } + + $port['stats']['ifInBits_rate'] = $port['stats']['ifInOctets_rate'] * 8; + $port['stats']['ifOutBits_rate'] = $port['stats']['ifOutOctets_rate'] * 8; + echo('bps('.formatRates($port['stats']['ifInBits_rate']).'/'.formatRates($port['stats']['ifOutBits_rate']).')'); + echo('bytes('.formatStorage($port['stats']['ifInOctets_diff']).'/'.formatStorage($port['stats']['ifOutOctets_diff']).')'); + echo('pkts('.format_si($port['stats']['ifInUcastPkts_rate']).'pps/'.format_si($port['stats']['ifOutUcastPkts_rate']).'pps)'); + + /// Port utilisation % threshold alerting. ## FIXME allow setting threshold per-port. probably 90% of ports we don't care about. + if ($config['alerts']['port_util_alert']) + { + // Check for port saturation of $config['alerts']['port_util_perc'] or higher. Alert if we see this. + // Check both inbound and outbound rates + $saturation_threshold = $this_port['ifSpeed'] * ( $config['alerts']['port_util_perc'] / 100 ); + echo("IN: " . $port['stats']['ifInBits_rate'] . " OUT: " . $port['stats']['ifOutBits_rate'] . " THRESH: " . $saturation_threshold); + if (($port['stats']['ifInBits_rate'] >= $saturation_threshold || $port['stats']['ifOutBits_rate'] >= $saturation_threshold) && $saturation_threshold > 0) + { + log_event('Port reached saturation threshold: ' . formatRates($port['stats']['ifInBits_rate']) . '/' . formatRates($port['stats']['ifOutBits_rate']) . ' - ifspeed: ' . formatRates( $this_port['stats']['ifSpeed']) , $device, 'interface', $port['interface_id']); + notify($device, 'Port saturation threshold reached on ' . $device['hostname'] , 'Port saturation threshold alarm: ' . $device['hostname'] . ' on ' . $port['ifDescr'] . "\nRates:" . formatRates($port['stats']['ifInBits_rate']) . '/' . formatRates($port['stats']['ifOutBits_rate']) . ' - ifspeed: ' . formatRates( $this_port['ifSpeed'])); + } + } + + /// Update RRDs + $rrdfile = $host_rrd . "/port-" . safename($port['ifIndex'] . ".rrd"); + if (!is_file($rrdfile)) + { + rrdtool_create($rrdfile," --step 300 \ + DS:INOCTETS:DERIVE:600:0:12500000000 \ + DS:OUTOCTETS:DERIVE:600:0:12500000000 \ + DS:INERRORS:DERIVE:600:0:12500000000 \ + DS:OUTERRORS:DERIVE:600:0:12500000000 \ + DS:INUCASTPKTS:DERIVE:600:0:12500000000 \ + DS:OUTUCASTPKTS:DERIVE:600:0:12500000000 \ + DS:INNUCASTPKTS:DERIVE:600:0:12500000000 \ + DS:OUTNUCASTPKTS:DERIVE:600:0:12500000000 \ + DS:INDISCARDS:DERIVE:600:0:12500000000 \ + DS:OUTDISCARDS:DERIVE:600:0:12500000000 \ + DS:INUNKNOWNPROTOS:DERIVE:600:0:12500000000 \ + DS:INBROADCASTPKTS:DERIVE:600:0:12500000000 \ + DS:OUTBROADCASTPKTS:DERIVE:600:0:12500000000 \ + DS:INMULTICASTPKTS:DERIVE:600:0:12500000000 \ + DS:OUTMULTICASTPKTS:DERIVE:600:0:12500000000 ".$config['rrd_rra']); + } + + foreach ($stat_oids as $oid) + { /// Copy values from array to global variables and force numeric. + $$oid = $this_port[$oid]; + if (!is_numeric($$oid)) { $$oid = "U"; } + } + + $if_rrd_update = "$polled:$ifInOctets:$ifOutOctets:$ifInErrors:$ifOutErrors:$ifInUcastPkts:$ifOutUcastPkts:$ifInNUcastPkts:$ifOutNUcastPkts:$ifInDiscards:$ifOutDiscards:$ifInUnknownProtos"; + $if_rrd_update .= ":$ifInBroadcastPkts:$ifOutBroadcastPkts:$ifInMulticastPkts:$ifOutMulticastPkts"; + $ret = rrdtool_update("$rrdfile", $if_rrd_update); + /// End Update IF-MIB + + /// Update PAgP + if ($this_port['pagpOperationMode'] || $port['pagpOperationMode']) + { + foreach ($pagp_oids as $oid) + { /// Loop the OIDs + if ($this_port[$oid] != $port[$oid]) + { /// If data has changed, build a query + $port['update'][$oid] = $this_port[$oid]; + echo("PAgP "); + log_event("$oid -> ".$this_port[$oid], $device, 'interface', $port['interface_id']); + } + } + } + /// End Update PAgP + + /// Do EtherLike-MIB + if ($config['enable_ports_etherlike']) { include("port-etherlike.inc.php"); } + + /// Do ADSL MIB + if ($config['enable_ports_adsl']) { include("port-adsl.inc.php"); } + + /// Do PoE MIBs + if ($config['enable_ports_poe']) { include("port-poe.inc.php"); } + + /// Do Alcatel Detailed Stats + if ($device['os'] == "aos") { include("port-alcatel.inc.php"); } + + /// Update Database + if (count($port['update'])) + { + $updated = dbUpdate($port['update'], 'ports', '`interface_id` = ?', array($port['interface_id'])); + if ($debug) { echo("$updated updated"); } + } + /// End Update Database + + /// Send alerts for interface flaps. + if ($config['alerts']['port']['ifdown'] && ($port['ifOperStatus'] != $this_port['ifOperStatus']) && $port['ignore'] == 0) + { + if ($this_port['ifAlias']) + { + $falias = preg_replace('/^"/', '', $this_port['ifAlias']); $falias = preg_replace('/"$/', '', $falias); $full = $this_port['ifDescr'] . " (" . $falias . ")"; + } else { + $full = $this_port['ifDescr']; + } + switch ($this_port['ifOperStatus']) + { + case "up": + notify($device, "Interface UP - " . $device['hostname'] . " - " . $full, "Device: " . $device['hostname'] . "\nInterface: " . $full); + break; + case "down": + notify($device, "Interface DOWN - " . $device['hostname'] . " - " . $full, "Device: " . $device['hostname'] . "\nInterface: " . $full); + break; + } + } + } + elseif ($port['disabled'] != "1") + { + echo("Port Deleted"); /// Port missing from SNMP cache. + if ($port['deleted'] != "1") + { + dbUpdate(array('deleted' => '1'), 'ports', '`device_id` = ? AND `ifIndex` = ?', array($device['device_id'], $port['ifIndex'])); + } + } else { + echo("Port Disabled."); + } + + echo("\n"); + + /// Clear Per-Port Variables Here + unset($this_port); +} + +/// Clear Variables Here +unset($port_stats); ?>