// -- i can make it a function, so that you don't know what it's doing. // -- $ports = adamasMagicFunction($ports_db); ? $query = 'SELECT * FROM `ports` WHERE `device_id` = ?'; //$ports_db = dbFetchRows($query, [ $device['device_id'] ]); // Termporary var, no need to assign $ports_attribs = get_device_entities_attribs($device['device_id'], 'port'); // Get all attribs //print_vars($ports_attribs); foreach (dbFetchRows($query, [$device['device_id']]) as $port) { if (isset($ports_attribs['port'][$port['port_id']])) { $port = array_merge($port, $ports_attribs['port'][$port['port_id']]); } $ports[$port['ifIndex']] = $port; } $ports_ignored_count_db = (int)get_entity_attrib('device', $device, 'ports_ignored_count'); // Cache last ports ignored count // Ports module options $ports_modules = []; // Ports sub-modules enabled/disabled foreach (array_keys($config) as $ports_module) { if (!str_starts($ports_module, 'enable_ports_')) { continue; } // Filter only enable_ports_* config entries $ports_module = str_replace('enable_ports_', '', $ports_module); //$ports_modules[$ports_module] = isset($attribs['enable_ports_' . $ports_module]) ? (bool)$attribs['enable_ports_' . $ports_module] : $config['enable_ports_' . $ports_module]; $ports_modules[$ports_module] = is_module_enabled($device, 'ports_' . $ports_module); } // Additionally, force enable separate walk feature for some device oses, but only if ports total count >10 $ports_module = 'separate_walk'; // Model definition can override os definition $model_separate_walk = isset($model['ports_' . $ports_module]) && $model['ports_' . $ports_module]; if (!$ports_modules[$ports_module] && $model_separate_walk) { if (isset($attribs['enable_ports_' . $ports_module]) && !$attribs['enable_ports_' . $ports_module]) { } // forcing disabled in device config else { $ports_total_count = $ports_ignored_count_db + dbFetchCell('SELECT COUNT(*) FROM `ports` WHERE `device_id` = ? AND `deleted` = 0', [$device['device_id']]); $ports_modules[$ports_module] = $ports_total_count > 10; if (OBS_DEBUG && $ports_modules[$ports_module]) { print_debug('Forced ports separate walk feature!'); } } } print_debug_vars($ports_modules); $table_rows = []; // Build SNMP Cache Array // IF-MIB OIDs that go into the ports table $data_oids_ifEntry = [ // ifEntry 'ifDescr', 'ifType', 'ifMtu', 'ifSpeed', 'ifPhysAddress', 'ifAdminStatus', 'ifOperStatus', 'ifLastChange', ]; $data_oids_ifXEntry = [ // ifXEntry 'ifName', 'ifAlias', 'ifHighSpeed', 'ifPromiscuousMode', 'ifConnectorPresent', ]; $data_oids = array_merge($data_oids_ifEntry, $data_oids_ifXEntry, [ 'ifDuplex', 'ifTrunk', 'ifVlan' ]); // Add additional oids // IF-MIB statistics OIDs that go into RRD $stat_oids_ifEntry = [ // ifEntry 'ifInOctets', 'ifOutOctets', 'ifInUcastPkts', 'ifOutUcastPkts', 'ifInNUcastPkts', 'ifOutNUcastPkts', // Note, (In|Out)NUcastPkts deprecated, for HC counters use Broadcast+Multicast instead 'ifInDiscards', 'ifOutDiscards', 'ifInErrors', 'ifOutErrors', 'ifInUnknownProtos', ]; $stat_oids_ifXEntry = [ // ifXEntry 'ifInMulticastPkts', 'ifOutMulticastPkts', 'ifInBroadcastPkts', 'ifOutBroadcastPkts', // HC counters 'ifHCInOctets', 'ifHCOutOctets', 'ifHCInUcastPkts', 'ifHCOutUcastPkts', 'ifHCInMulticastPkts', 'ifHCOutMulticastPkts', 'ifHCInBroadcastPkts', 'ifHCOutBroadcastPkts', ]; // This oids definitions used only for Upstream/Downstream interface types $upstream_oids = [ // ifEntry 'ifInOctets', 'ifInUcastPkts', 'ifInNUcastPkts', 'ifInDiscards', 'ifInErrors', // ifXEntry 'ifInMulticastPkts', 'ifInBroadcastPkts', 'ifHCInOctets', 'ifHCInUcastPkts', 'ifHCInMulticastPkts', 'ifHCInBroadcastPkts', ]; $downstream_oids = [ // ifEntry 'ifOutOctets', 'ifOutUcastPkts', 'ifOutNUcastPkts', 'ifOutDiscards', 'ifOutErrors', // ifXEntry 'ifOutMulticastPkts', 'ifOutBroadcastPkts', 'ifHCOutOctets', 'ifHCOutUcastPkts', 'ifHCOutMulticastPkts', 'ifHCOutBroadcastPkts', ]; // Remove HC oids from stat arrays for SNMP v1 or 64bit module disabled if ($device['snmp_version'] === 'v1' || !$ports_modules['64bit']) { $hc_oids = [ // HC counters 'ifHCInOctets', 'ifHCOutOctets', 'ifHCInUcastPkts', 'ifHCOutUcastPkts', 'ifHCInMulticastPkts', 'ifHCOutMulticastPkts', 'ifHCInBroadcastPkts', 'ifHCOutBroadcastPkts', ]; $stat_oids_ifXEntry = array_diff($stat_oids_ifXEntry, $hc_oids); $upstream_oids = array_diff($upstream_oids, $hc_oids); $downstream_oids = array_diff($downstream_oids, $hc_oids); } // Merge stat oids $stat_oids = array_merge($stat_oids_ifEntry, $stat_oids_ifXEntry); // PAgP OIDs // PAgP disabled since r7987, while not moved to new polling style //$pagp_oids = array('pagpOperationMode', 'pagpPortState', 'pagpPartnerDeviceId', 'pagpPartnerLearnMethod', 'pagpPartnerIfIndex', 'pagpPartnerGroupIfIndex', // 'pagpPartnerDeviceName', 'pagpEthcOperationMode', 'pagpDeviceId', 'pagpGroupIfIndex'); //$ifmib_oids = array_merge($data_oids, $stat_oids); print_cli_data_field("Caching Oids"); $port_stats = []; $include_stats = []; if (is_device_mib($device, "IF-MIB")) { $inc_start = microtime(TRUE); // MIB timing start if (!$ports_modules['separate_walk']) { print_debug("Used full table ifEntry/ifXEntry snmpwalk."); $ifmib_oids = [ 'ifEntry', 'ifXEntry' ]; foreach ($ifmib_oids as $oid) { $has_name = 'has_' . $oid; echo("$oid "); // End walk before Oid have effect only for nobulk! if ($oid === 'ifEntry') { // stop walk after ifOutErrors (next ifOutQLen) snmpwalk_oid_end('ifOutQLen'); } else { // stop walk after ifAlias (next ifCounterDiscontinuityTime) snmpwalk_oid_end('ifCounterDiscontinuityTime'); } $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "IF-MIB"); $$has_name = snmp_status() || snmp_error_code() === OBS_SNMP_ERROR_REQUEST_NOT_COMPLETED; // $has_ifEntry, $has_ifXEntry //print_vars($$has_name); if ($oid === 'ifEntry') { // Store error_code, 1000 == not exist table, 2 and 3 - not complete request $has_ifEntry_error_code = snmp_error_code(); } } } else { print_debug("Used separate data tables snmpwalk and per port snmpget."); $has_ifEntry = FALSE; // Data fields // ifDescr, ifAlias, ifName, ifType, ifOperStatus foreach ([ 'ifDescr', 'ifType', 'ifOperStatus', 'ifAdminStatus' ] as $oid) { echo("$oid "); $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "IF-MIB"); $has_ifEntry = $has_ifEntry || snmp_status(); $has_ifEntry_error_code = snmp_error_code(); } $has_ifXEntry = FALSE; foreach ([ 'ifAlias', 'ifName', 'ifHighSpeed' ] as $oid) { echo("$oid "); $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "IF-MIB"); $has_ifXEntry = $has_ifXEntry || snmp_status(); } // Per port snmpget if ($port_stats) { // Collect oids for per port snmpget if ($has_ifXEntry) { $port_oids = array_merge($stat_oids_ifXEntry, $stat_oids_ifEntry); $port_oids = array_merge($port_oids, array_diff($data_oids_ifEntry, [ 'ifDescr', 'ifType', 'ifOperStatus', 'ifAdminStatus' ])); $port_oids = array_merge($port_oids, array_diff($data_oids_ifXEntry, [ 'ifAlias', 'ifName', 'ifHighSpeed' ])); } else { $port_oids = array_merge($stat_oids_ifEntry, array_diff($data_oids_ifEntry, [ 'ifDescr', 'ifType', 'ifOperStatus' ])); } // Use snmpget for each (not ignored) port // NOTE. This method reduce polling time when too many ports (>100) echo(implode(' ', $port_oids) . ", ifIndex: "); foreach ($port_stats as $ifIndex => $port) { $port_disabled = isset($ports[$ifIndex]['disabled']) && $ports[$ifIndex]['disabled']; // Port polling disabled from WUI // On some Brocade NOS if ($port['ifOperStatus'] === '-1') { $port['ifOperStatus'] = 'unknown'; } if (!$port_disabled && is_port_valid($device, $port)) { echo("\nifIndex $ifIndex (ifAdminStatus = {$port['ifAdminStatus']}, ifOperStatus = {$port['ifOperStatus']}). "); // Skip get snmp data when port down and not changed from previous $port_skip_data = $ports[$ifIndex]['ifOperStatus'] === $port['ifOperStatus'] && $ports[$ifIndex]['ifAdminStatus'] === $port['ifAdminStatus'] && ($port['ifOperStatus'] === 'down' || $port['ifOperStatus'] === 'lowerLayerDown' || $port['ifOperStatus'] === 'notPresent' || $port['ifAdminStatus'] === 'down'); if ($port_skip_data) { print_debug("Skipped snmpget for ifOperStatus or ifAdminStatus down"); $port_has_64bit = $device['snmp_version'] !== 'v1' && $ports_modules['64bit'] && $ports[$ifIndex]['port_64bit']; foreach ($port_oids as $port_oid) { // Copy previous values if ($port_has_64bit && str_starts_with($port_oid, 'ifHC')) { // Copy HC counter $port_oid_old = str_replace('ifHC', 'if', $port_oid); $port_stats[$ifIndex][$port_oid] = $ports[$ifIndex][$port_oid_old]; } else { $port_stats[$ifIndex][$port_oid] = $ports[$ifIndex][$port_oid] ?? '0'; // ifInUnknownProtos not stored in db } } print_debug_vars($port_stats[$ifIndex]); } else { $port_oid = implode(".$ifIndex ", $port_oids) . ".$ifIndex"; $port_stats = snmp_get_multi_oid($device, $port_oid, $port_stats, "IF-MIB"); } } } } } // MIB timing $include_stats['IF-MIB'] = elapsed_time($inc_start); // End IF-MIB permitted } //else { // This part for devices who not have IF-MIB stats, but have own vendor tree with ports //} echo PHP_EOL; // End IF-MIB section ////////// $private_stats = []; foreach (get_device_mibs_permitted($device) as $mib) { $private_stats[] = merge_private_mib($device, 'ports', $mib, $port_stats, NULL); } $include_stats = array_merge($include_stats, ...$private_stats); unset($private_stats); print_debug_vars($include_stats); //////// // Prevent mark ports as DELETED when ifEntry snmpwalk return not complete data! $allow_delete_ports = $has_ifEntry_error_code !== OBS_SNMP_ERROR_REQUEST_NOT_COMPLETED && $has_ifEntry_error_code !== OBS_SNMP_ERROR_TOO_LONG_RESPONSE; // Store polled time exactly after walk IF-MIB, for more correct port speed calculate! $polled = time(); // Device uptime and polled time (required for ifLastChange) if (isset($cache['devices']['uptime'][$device['device_id']])) { $device_uptime = &$cache['devices']['uptime'][$device['device_id']]; } else { print_error("Device uptime not cached, ifLastChange will incorrect. Check polling system module."); } // Subset of IF-MIB OIDs that we put into the state table $stat_oids_db = [ 'ifInOctets', 'ifOutOctets', 'ifInErrors', 'ifOutErrors', 'ifInUcastPkts', 'ifOutUcastPkts', 'ifInNUcastPkts', 'ifOutNUcastPkts', 'ifInBroadcastPkts', 'ifOutBroadcastPkts', 'ifInMulticastPkts', 'ifOutMulticastPkts', 'ifInDiscards', 'ifOutDiscards' ]; // Subset of IF-MIB OIDs that we put into the ports table $data_oids_db = array_diff($data_oids, ['ifLastChange']); // remove ifLastChange, because it added separate $data_oids_db = array_merge($data_oids_db, ['port_label', 'port_label_short', 'port_label_base', 'port_label_num']); // Additional MIBS and modules $process_port_functions = []; // collect processing functions $process_port_db = []; // collect processing db fields // Additionally include per MIB functions and snmpwalks (uses include_once) $port_stats_count = safe_count($port_stats); $include_lib = TRUE; $include_dir = "includes/polling/ports/"; include("includes/include-dir-mib.inc.php"); if (!safe_empty($include_stats)) { // Set per mib polling times $device_state['poller_ports_perf'] = $include_stats; } print_debug_vars($include_stats); unset($include_stats); if (safe_count($port_stats)) { // If the device is cisco, pull a few cisco-specific MIBs and try to get vlan data from CISCO-VTP-MIB /* PAgP disabled since r7987, while not moved to new polling style if ($device['os_group'] === "cisco") { //FIXME. All PAGP operations should be moved to separate "stacks" module and separate table (not in ports table) foreach ($pagp_oids as $oid) { $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "CISCO-PAGP-MIB"); // Break if no PAGP tables on device if ($oid == 'pagpOperationMode' && $GLOBALS['snmp_status'] === FALSE) { break; } } } */ // End Building SNMP Cache Array $graphs['bits'] = TRUE; // Create global device_bits graph, since we have ports. print_debug_vars($port_stats); } // New interface detection $ports_ignored_count = 0; // Counting ignored ports $ports_deleted_count = 0; // Counting deleted ports $ports_db_deleted = []; // MultiUpdate deleted ports db $ports_db_state = []; // MultiUpdate state ports db foreach ($port_stats as $ifIndex => $port) { // Always use ifIndex from index part (not from Oid!), // Oid can have incorrect ifIndex, ie: // ifIndex.0 = 1 $port['ifIndex'] = $ifIndex; // On some Brocade NOS if ($port['ifOperStatus'] === '-1') { $port['ifOperStatus'] = 'unknown'; } if (is_port_valid($device, $port)) { if (!is_array($ports[$port['ifIndex']])) { $port_insert = ['device_id' => $device['device_id'], 'ifIndex' => $ifIndex, 'ignore' => isset($port['ignore']) ? $port['ignore'] : '0', 'disabled' => isset($port['disabled']) ? $port['disabled'] : '0']; $port_id = dbInsert(['device_id' => $device['device_id'], 'ifIndex' => $ifIndex], 'ports'); $ports[$port['ifIndex']] = dbFetchRow("SELECT * FROM `ports` WHERE `port_id` = ?", [$port_id]); print_message("Adding: " . $port['ifDescr'] . "(" . $ifIndex . ")(" . $ports[$port['ifIndex']]['port_id'] . ")"); } elseif ($ports[$ifIndex]['deleted'] == "1") { $ports_db_deleted[] = [ // UNIQUE fields 'port_id' => $ports[$ifIndex]['port_id'], 'ifIndex' => $ifIndex, 'device_id' => $device['device_id'], // Update this fields 'deleted' => '0', 'ifLastChange' => date('Y-m-d H:i:s', $polled) ]; log_event("Interface DELETED mark removed", $device, 'port', $ports[$ifIndex]); $ports[$ifIndex]['deleted'] = "0"; } } else { if (isset($ports[$port['ifIndex']]) && $ports[$port['ifIndex']]['deleted'] != '1' && $allow_delete_ports) { $ports_db_deleted[] = [ // UNIQUE fields 'port_id' => $ports[$ifIndex]['port_id'], 'ifIndex' => $ifIndex, 'device_id' => $device['device_id'], // Update this fields 'deleted' => '1', 'ifLastChange' => date('Y-m-d H:i:s', $polled) ]; //log_event("Interface was marked as DELETED", $device, 'port', $ports[$ifIndex]); $ports[$ifIndex]['deleted'] = "1"; $ports_deleted_count++; } $ports_ignored_count++; // Counting ignored ports } } if (!$allow_delete_ports) { log_event("WARNING! Ports snmpwalk did not complete. Try to increase SNMP timeout on the device properties page.", $device, 'device', $device['device_id'], 7); } elseif ($ports_deleted_count > 0) { // Recheck device is snmpable, can be case when device down while polling $device['snmpable'] = is_snmpable($device); if (!$device['snmpable']) { // When device down, prevent other ports updates log_event("WARNING! Poll ports ended prematurely because the device became unavailable. Try to increase SNMP timeout on the device properties page.", $device, 'device', $device['device_id'], 7); $device['status'] = 0; return; } foreach ($ports_db_deleted as $entry) { if ($entry['deleted'] == '1') { log_event("Interface was marked as DELETED", $device, 'port', $entry['port_id']); } } } if ($ports_ignored_count !== $ports_ignored_count_db) { set_entity_attrib('device', $device, 'ports_ignored_count', $ports_ignored_count); } // End New interface detection echo(PHP_EOL . PHP_EOL); // Loop ports in the DB and update where necessary foreach ($ports as $port) { // Notes: // $port_stats - array of ports from snmpwalks // $this_port - link to port array from snmpwalk // $ports - array of ports based on current db entries // $port - current port array from db if ($port['deleted']) { continue; } // Skip updating RRDs and DB if interface marked as DELETED (also skipped bad_if's) if ($port_stats[$port['ifIndex']] && $port['disabled'] != "1") { // Check to make sure Port data is cached. $this_port = &$port_stats[$port['ifIndex']]; $port['update'] = []; $port['state'] = []; // State field for update // Poll time and period if (isset($this_port['polled']) && is_intnum($this_port['polled']) && ($this_port['polled'] > OBS_MIN_UNIXTIME)) { // See SPECTRA-LOGIC-STRATA-MIB definition } else { $this_port['polled'] = $polled; } $polled_period = $this_port['polled'] - $port['poll_time']; $port['state']['poll_time'] = $this_port['polled']; $port['state']['poll_period'] = $polled_period; // $polled_period = $polled - $port['poll_time']; // $port['state']['poll_time'] = $polled; // $port['state']['poll_period'] = $polled_period; $this_port['port_id'] = $port['port_id']; $this_port['ifIndex'] = $port['ifIndex']; $this_port_indexes = ['port_id' => $ports[$port['ifIndex']]['port_id'], 'ifIndex' => $port['ifIndex'], 'device_id' => $device['device_id']]; // UNIQUE port indexes // Store original port walked OIDs for debugging later if ($config['debug_port']['spikes'] || $config['debug_port'][$port['port_id']]) { $debug_port = $this_port; // DEBUG } //print_vars($process_port_functions); foreach ($process_port_functions as $func => $ok) { if ($ok && function_exists('process_port_' . $func)) { if (OBS_DEBUG > 1) { print_debug("Processing port ifIndex " . $this_port['ifIndex'] . " with function process_port_{$func}() "); } // Note, used call by array, because parameters for call_user_func() are not passed by reference call_user_func_array('process_port_' . $func, [&$this_port, $device, $port]); } } /* Start process_port_label() */ // Before process_port_label() // Fix ord (UTF-8) chars, ie: // ifAlias.3 = Conexin de rea local* 3 foreach ([ 'ifAlias', 'ifDescr', 'ifName' ] as $oid_fix) { if (!isset($this_port[$oid_fix]) || ($oid_fix !== 'ifAlias' && is_hex_string($this_port[$oid_fix]))) { // In cases, when device have memory leak, they return hex string instead UTF, rewritten in process_port_label() continue; } $this_port[$oid_fix] = snmp_fix_string($this_port[$oid_fix]); } process_port_label($this_port, $device); /* End process_port_label() */ //print_vars($this_port); # // Copy ifHC[In|Out] values to non-HC if they exist # // Check if they're greater than zero to work around stupid devices which expose HC counters, but don't populate them. HERPDERP. - adama # if ($device['os'] == "netapp") { $hc_prefixes = array('HC', '64'); } else { $hc_prefixes = array('HC'); } # foreach ($hc_prefixes as $hc_prefix) # { # foreach (array('Octets', 'UcastPkts', 'BroadcastPkts', 'MulticastPkts') as $hc) # { # $hcin = 'if'.$hc_prefix.'In'.$hc; # $hcout = 'if'.$hc_prefix.'Out'.$hc; # if (is_numeric($this_port[$hcin]) && $this_port[$hcin] > 0 && is_numeric($this_port[$hcout]) && $this_port[$hcout] > 0) # { # // echo(" ".$hc_prefix." $hc, "); # $this_port['ifIn'.$hc] = $this_port[$hcin]; # $this_port['ifOut'.$hc] = $this_port[$hcout]; # } # } # } // Here special checks for Upstream/Downstream ports, because it have only In or only Out counters if (str_contains($this_port['ifType'], 'Upstream')) { // Upstream has only In counters foreach ($upstream_oids as $oid_in) { $oid_out = str_replace('In', 'Out', $oid_in); if (is_numeric($this_port[$oid_in]) && !is_numeric($this_port[$oid_out])) { $this_port[$oid_out] = 0; // Set it all to zero } } } elseif (str_contains($this_port['ifType'], 'Downstream')) { // Downstream has only Out counters foreach ($downstream_oids as $oid_out) { $oid_in = str_replace('Out', 'In', $oid_out); if (is_numeric($this_port[$oid_out]) && !is_numeric($this_port[$oid_in])) { $this_port[$oid_in] = 0; // Set it all to zero } } } // If we're not using SNMPv1, assume there are 64-bit values and overwrite the 32-bit OIDs. if ($device['snmp_version'] !== 'v1' && $ports_modules['64bit']) { $hc_prefix = 'HC'; $port_has_64bit = is_numeric($this_port['if' . $hc_prefix . 'InOctets']) && is_numeric($this_port['if' . $hc_prefix . 'OutOctets']); // We've never tested for 64bit. Lets do it now. Lots of devices seem to not support 64bit counters for all ports. if (safe_empty($port['port_64bit'])) { // We have 64-bit traffic counters. Lets set port_64bit if ($port_has_64bit) { $port['port_64bit'] = 1; $port['update']['port_64bit'] = 1; } else { $port['port_64bit'] = 0; $port['update']['port_64bit'] = 0; } } elseif ($has_ifXEntry && $port_has_64bit && !$port['port_64bit']) { // Port changed to 64-bit $port['port_64bit'] = 1; $port['update']['port_64bit'] = 1; log_event('Interface changed: [HC] 64bit counters enabled (may cause disposable spike)', $device, 'port', $port); } $port_has_mcbc = is_numeric($this_port['ifInBroadcastPkts']) && is_numeric($this_port['ifOutBroadcastPkts']) && is_numeric($this_port['ifInMulticastPkts']) && is_numeric($this_port['ifOutMulticastPkts']); if ($port['port_mcbc'] == NULL) { // We have Broadcast/Multicast traffic counters. Let's set port_mcbc if ($port_has_mcbc) { $port['port_mcbc'] = 1; $port['update']['port_mcbc'] = 1; } else { $port['port_mcbc'] = 0; $port['update']['port_mcbc'] = 0; } } elseif ($has_ifXEntry && $port_has_mcbc && !$port['port_mcbc']) { // Port acquired multicast/broadcast! $port['port_mcbc'] = 1; $port['update']['port_mcbc'] = 1; log_event('Interface changed: Separated Multicast/Broadcast statistics appeared.', $device, 'port', $port); } //elseif (!$port_has_64bit && $port['port_64bit']) //{ // // Port changed to 32-bit // $port['port_64bit'] = 0; // $port['update']['port_64bit'] = 0; // log_event('Interface changed: [HC] -> Counter32', $device, 'port', $port); //} if ($port['port_64bit']) { print_debug("64-bit, "); foreach ([ 'Octets', 'UcastPkts', 'BroadcastPkts', 'MulticastPkts' ] as $hc) { $hcin = 'if' . $hc_prefix . 'In' . $hc; $hcout = 'if' . $hc_prefix . 'Out' . $hc; $this_port['ifIn' . $hc] = $this_port[$hcin]; $this_port['ifOut' . $hc] = $this_port[$hcout]; } // Additionally override (In|Out)NUcastPkts // see: http://jira.observium.org/browse/OBSERVIUM-1749 $this_port['ifInNUcastPkts'] = int_add($this_port['ifInBroadcastPkts'], $this_port['ifInMulticastPkts']); $this_port['ifOutNUcastPkts'] = int_add($this_port['ifOutBroadcastPkts'], $this_port['ifOutMulticastPkts']); } } elseif ($port['port_64bit']) { $port['port_64bit'] = 0; $port['update']['port_64bit'] = 0; if ($port['port_mcbc']) { $port['port_mcbc'] = 0; $port['update']['port_mcbc'] = 0; } log_event('Interface changed: [HC] 64bit counters disabled (may cause disposable spike)', $device, 'port', $port); } // rewrite the ifPhysAddress // IF-MIB::ifPhysAddress.2 = STRING: 66:c:9b:1b:62:7e // IF-MIB::ifPhysAddress.2 = Hex-STRING: 00 02 99 09 E9 84 // deeerp device return snmp string instead mac // ifPhysAddress.3 = 30:30:2d:30:36:2d:33:39:2d:30:41:2d:35:46:2d:36:38 // ifPhysAddress.3 = STRING: "00-06-39-0A-5F-68" $this_port['ifPhysAddress'] = mac_zeropad($this_port['ifPhysAddress']); // ifSpeed processing process_port_speed($this_port, $device, $port); $port['alert_array']['ifSpeed'] = is_numeric($this_port['ifSpeed']) ? $this_port['ifSpeed'] : 0; if (is_numeric($this_port['ifHighSpeed'])) { $port['alert_array']['ifHighSpeed'] = $this_port['ifHighSpeed']; } // Simple override of ifAlias -- mostly for testing if (isset($config['ports']['ifAlias_map']['ifIndex'][$device['hostname']][$port['ifIndex']])) { $this_port['ifAlias'] = $config['ports']['ifAlias_map']['ifIndex'][$device['hostname']][$port['ifIndex']]; } if (isset($config['ports']['ifAlias_map']['ifName'][$device['hostname']][$port['ifName']])) { $this_port['ifAlias'] = $config['ports']['ifAlias_map']['ifName'][$device['hostname']][$port['ifName']]; } // Update TrustSec if ($this_port['encrypted']) { if ($port['encrypted'] === '0') { log_event("Interface is now encrypted", $device, 'port', $port); $port['update']['encrypted'] = '1'; } } elseif ($port['encrypted'] === '1') { log_event("Interface is no longer encrypted", $device, 'port', $port); $port['update']['encrypted'] = '0'; } // Make sure ifOperStatus is valid (FIXME. not exist statuses already "filtered" in is_port_valid()) if (isset($this_port['ifOperStatus']) && !in_array($this_port['ifOperStatus'], [ 'testing', 'notPresent', 'dormant', 'down', 'lowerLayerDown', 'unknown', 'up', 'monitoring' ])) { $this_port['ifOperStatus'] = 'unknown'; } if (isset($this_port['ifAdminStatus']) && !in_array($this_port['ifAdminStatus'], [ 'up', 'down', 'testing' ])) { $this_port['ifAdminStatus'] = ''; // or NULL? } if (isset($this_port['ifConnectorPresent']) && !in_array($this_port['ifConnectorPresent'], [ 'true', 'false' ])) { $this_port['ifConnectorPresent'] = NULL; } // Update IF-MIB data $log_event = []; foreach ($data_oids_db as $oid) { if ($port[$oid] != $this_port[$oid]) { if (isset($this_port[$oid])) { $port['update'][$oid] = $this_port[$oid]; $msg = "[$oid] '" . $port[$oid] . "' -> '" . $this_port[$oid] . "'"; } else { $port['update'][$oid] = ['NULL']; $msg = "[$oid] '" . $port[$oid] . "' -> NULL"; } if ($oid === 'ifOperStatus' && ($port[$oid] === 'up' || $port[$oid] === 'down') && isset($this_port[$oid])) { // Specific log_event for port Up/Down log_event('Interface ' . ucfirst($this_port[$oid]) . ": [$oid] '" . $port[$oid] . "' -> '" . $this_port[$oid] . "'", $device, 'port', $port, 'warning'); } else { $log_event[] = $msg; } if (OBS_DEBUG) { echo($msg . " "); } // else { echo($oid . " "); } } } // ifLastChange if (isset($this_port['ifLastChange']) && $this_port['ifLastChange'] != '') { // Convert ifLastChange from timetick to timestamp /** * The value of sysUpTime at the time the interface entered * its current operational state. If the current state was * entered prior to the last re-initialization of the local * network management subsystem, then this object contains a * zero value. * * NOTE, observium uses last change timestamp. */ $if_lastchange_uptime = timeticks_to_sec($this_port['ifLastChange']); if (preg_match(OBS_PATTERN_TIMESTAMP, $this_port['ifLastChange'])) { // This ifLastChange copied from previous $if_lastchange_uptime = TRUE; } elseif (($device_uptime['sysUpTime'] - $if_lastchange_uptime) > 90) { $if_lastchange = $device_uptime['polled'] - $device_uptime['sysUpTime'] + $if_lastchange_uptime; print_debug('IFLASTCHANGE = ' . $device_uptime['polled'] . 's - ' . $device_uptime['sysUpTime'] . 's + ' . $if_lastchange_uptime . 's'); if (abs($if_lastchange - strtotime($port['ifLastChange'])) > 90) { // Compare lastchange with previous, update only if more than 60 sec (for exclude random dispersion) $port['update']['ifLastChange'] = date('Y-m-d H:i:s', $if_lastchange); // Convert to timestamp } } else { // Device sysUpTime more than if uptime or too small difference.. impossible, seems as bug on device $if_lastchange_uptime = FALSE; } } else { // ifLastChange not exist $if_lastchange_uptime = FALSE; } if ($if_lastchange_uptime === FALSE) { if (empty($port['ifLastChange']) || $port['ifLastChange'] === '0000-00-00 00:00:00' || // Newer set (first time) isset($port['update']['ifOperStatus']) || isset($port['update']['ifAdminStatus']) || isset($port['update']['ifSpeed']) || isset($port['update']['ifDuplex'])) { $port['update']['ifLastChange'] = date('Y-m-d H:i:s', $this_port['polled']); } print_debug("IFLASTCHANGE unknown/false, used system times."); } if (isset($port['update']['ifLastChange'])) { print_debug("IFLASTCHANGE (" . $port['ifIndex'] . "): " . $port['update']['ifLastChange']); if ($port['ifLastChange'] && $port['ifLastChange'] !== '0000-00-00 00:00:00' && safe_count($log_event)) { $log_event[] = "[ifLastChange] '" . $port['ifLastChange'] . "' -> '" . $port['update']['ifLastChange'] . "'"; } } if ((bool)$log_event) { log_event('Interface changed: ' . implode('; ', $log_event), $device, 'port', $port); } // Parse description (usually ifAlias) if config option set if ($custom_port_parser) { $log_event = []; if ($custom_port_parser !== 'old') { $port_ifAlias = custom_port_parser($this_port); } else { $custom_port_attribs = ['type', 'descr', 'circuit', 'speed', 'notes']; include($config['install_dir'] . "/" . $config['port_descr_parser']); } foreach ($custom_port_attribs as $attrib) { $attrib_key = "port_descr_" . $attrib; if ($port_ifAlias[$attrib] != $port[$attrib_key]) { if (isset($port_ifAlias[$attrib])) { $port['update'][$attrib_key] = $port_ifAlias[$attrib]; $msg = "[$attrib] " . $port[$attrib_key] . " -> " . $port_ifAlias[$attrib]; } else { $port['update'][$attrib_key] = ['NULL']; $msg = "[$attrib] " . $port[$attrib_key] . " -> NULL"; } $log_event[] = $msg; } } if ((bool)$log_event) { log_event('Interface changed (attrib): ' . implode('; ', $log_event), $device, 'port', $port); } } // End parse ifAlias // Update IF-MIB metrics foreach ($stat_oids_db as $oid) { calculate_port_oid_stats($this_port, $port, $oid, $polled_period); } if ($config['statsd']['enable']) { // Update StatsD/Carbon foreach ($stat_oids as $oid) { if (!str_contains($oid, "HC") && is_numeric($this_port[$oid])) { StatsD::gauge(str_replace(".", "_", $device['hostname']) . '.' . 'port' . '.' . $port['ifIndex'] . '.' . $oid, $this_port[$oid]); } } } // If we have been told to debug this port, output the counters we collected earlier, with the rates stuck on the end. debug_port($device, $this_port, $debug_port, $port, $hc_prefix, $polled_period); // Put States into alert array foreach ([ 'ifOperStatus', 'ifAdminStatus', 'ifMtu', 'ifDuplex', 'ifVlan' ] as $oid) { if (isset($this_port[$oid])) { $port['alert_array'][$oid] = $this_port[$oid]; } } // Store average in/out packets size if ($in_pkts_delta = int_add($port['alert_array']['ifInUcastPkts_delta'], $port['alert_array']['ifInNUcastPkts_delta'])) { $port['alert_array']['rx_ave_pktsize'] = $port['alert_array']['ifInOctets_delta'] / $in_pkts_delta; } else { $port['alert_array']['rx_ave_pktsize'] = 0; } if ($out_pkts_delta = int_add($port['alert_array']['ifOutUcastPkts_delta'], $port['alert_array']['ifOutNUcastPkts_delta'])) { $port['alert_array']['tx_ave_pktsize'] = $port['alert_array']['ifOutOctets_delta'] / $out_pkts_delta; } else { $port['alert_array']['tx_ave_pktsize'] = 0; } // Store aggregate in/out state $port['state']['ifOctets_rate'] = $port['stats']['ifOutOctets_rate'] + $port['stats']['ifInOctets_rate']; $port['state']['ifUcastPkts_rate'] = $port['stats']['ifOutUcastPkts_rate'] + $port['stats']['ifInUcastPkts_rate']; $port['state']['ifErrors_rate'] = $port['stats']['ifOutErrors_rate'] + $port['stats']['ifInErrors_rate']; $port['state']['ifDiscards_rate'] = $port['stats']['ifOutDiscards_rate'] + $port['stats']['ifInDiscards_rate']; // Send aggregate data to alerter too $port['alert_array']['ifOctets_rate'] = $port['state']['ifOctets_rate']; $port['alert_array']['ifUcastPkts_rate'] = $port['state']['ifUcastPkts_rate']; $port['alert_array']['ifNUcastPkts_rate'] = $port['stats']['ifOutNUcastPkts_rate'] + $port['stats']['ifInNUcastPkts_rate']; $port['alert_array']['ifErrors_rate'] = $port['state']['ifErrors_rate']; $port['alert_array']['ifBroadcastPkts_rate'] = $port['stats']['ifOutBroadcastPkts_rate'] + $port['stats']['ifInBroadcastPkts_rate']; $port['alert_array']['ifMulticastPkts_rate'] = $port['stats']['ifOutMulticastPkts_rate'] + $port['stats']['ifInMulticastPkts_rate']; $port['alert_array']['ifDiscards_rate'] = $port['state']['ifDiscards_rate']; print_debug_vars($port['alert_array']); // Set per port RRD options $rrd_options = [ 'speed' => $this_port['ifSpeed'] ]; // Grow max for ports with 40G+ ifSpeed if (isset($port['update']['ifSpeed']) && $port['update']['ifSpeed'] > 40000000000) { //$rrd_options['speed'] += 20000000000; // DEBUG $rrd_options['update_max'] = TRUE; } // Update RRDs rrdtool_update_ng($device, 'port', [ 'INOCTETS' => $this_port['ifInOctets'], 'OUTOCTETS' => $this_port['ifOutOctets'], 'INERRORS' => $this_port['ifInErrors'], 'OUTERRORS' => $this_port['ifOutErrors'], 'INUCASTPKTS' => $this_port['ifInUcastPkts'], 'OUTUCASTPKTS' => $this_port['ifOutUcastPkts'], 'INNUCASTPKTS' => $this_port['ifInNUcastPkts'], 'OUTNUCASTPKTS' => $this_port['ifOutNUcastPkts'], 'INDISCARDS' => $this_port['ifInDiscards'], 'OUTDISCARDS' => $this_port['ifOutDiscards'], 'INUNKNOWNPROTOS' => $this_port['ifInUnknownProtos'], 'INBROADCASTPKTS' => $this_port['ifInBroadcastPkts'], 'OUTBROADCASTPKTS' => $this_port['ifOutBroadcastPkts'], 'INMULTICASTPKTS' => $this_port['ifInMulticastPkts'], 'OUTMULTICASTPKTS' => $this_port['ifOutMulticastPkts'], ], get_port_rrdindex($port), TRUE, $rrd_options); // End Update IF-MIB // Update additional MIBS and modules foreach ($process_port_db as $port_module => $oids) { $log_event = []; foreach ($oids as $oid) { if ($port[$oid] != $this_port[$oid]) { if (isset($this_port[$oid])) { // Changed Oid $port['update'][$oid] = $this_port[$oid]; $msg = "[$oid] '" . $port[$oid] . "' -> '" . $this_port[$oid] . "'"; } else { // Removed/empty Oid $port['update'][$oid] = ['NULL']; $msg = "[$oid] '" . $port[$oid] . "' -> NULL"; } $log_event[] = $msg; if (OBS_DEBUG) { echo($msg . " "); } } } if ((bool)$log_event) { log_event('Interface changed (' . $port_module . '): ' . implode('; ', $log_event), $device, 'port', $port); } } // End update additional MIBS /* PAgP disabled since r7987, while not moved to new polling style // Update PAgP if ($this_port['pagpOperationMode'] || $port['pagpOperationMode']) { $log_event = []; 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]; $log_event[] = "[$oid] " . $port[$oid] . " -> " . $this_port[$oid]; } } if ((bool)$log_event) { log_event('Interface changed (pagp): ' . implode('; ', $log_event), $device, 'port', $port); } } // End Update PAgP */ # if (OBS_DEBUG > 1) { print_vars($port['alert_array']); echo(PHP_EOL); print_vars($this_port);} check_entity('port', $port, $port['alert_array']); // Send statistics array via AMQP/JSON if AMQP is enabled globally and for the ports module if ($config['amqp']['enable'] == TRUE && $config['amqp']['modules']['ports']) { $json_data = array_merge($this_port, $port['state']); unset($json_data['rrd_update']); // FIXME unset no longer needed when switched to rrdtool_update_ng() ! messagebus_send(['attribs' => ['t' => $this_port['polled'], 'device' => $device['hostname'], 'device_id' => $device['device_id'], 'e_type' => 'port', 'e_index' => $port['ifIndex']], 'data' => $json_data]); unset($json_data); } // Unified state update //$port['update'] = array_merge($port['state'], $port['update']); //$updated = dbUpdate($port['update'], 'ports', '`port_id` = ?', array($port['port_id'])); // Add to MultiUpdate ports state as single query $ports_db_state[] = array_merge($this_port_indexes, $port['state']); // Update Database if (!safe_empty($port['update'])) { $updated = dbUpdate($port['update'], 'ports', '`port_id` = ?', [$port['port_id']]); //print_debug("PORT updated rows=$updated"); } // Add table row $table_row = []; $table_row[] = $port['ifIndex']; $table_row[] = $port['port_label_short']; $table_row[] = rewrite_iftype($port['ifType']); $table_row[] = format_bps($port['ifSpeed']); $table_row[] = format_bps($port['stats']['ifInBits_rate']); $table_row[] = format_bps($port['stats']['ifOutBits_rate']); $table_row[] = format_bytes($port['stats']['ifInOctets_diff']); $table_row[] = format_bytes($port['stats']['ifOutOctets_diff']); $table_row[] = format_si($port['stats']['ifInUcastPkts_rate']); $table_row[] = format_si($port['stats']['ifOutUcastPkts_rate']); $table_row[] = ($port['port_64bit'] ? "%gY%w" : "%rN%w"); $table_rows[] = $table_row; unset($table_row); // End Update Database } elseif ($port['disabled'] != "1") { print_message("Port Deleted."); // Port missing from SNMP cache. if (isset($port['ifIndex']) && $port['deleted'] != "1") { $ports_db_deleted[] = ['port_id' => $ports[$port['ifIndex']]['port_id'], 'ifIndex' => $port['ifIndex'], 'device_id' => $device['device_id'], // UNIQUE fields 'deleted' => '1', 'ifLastChange' => date('Y-m-d H:i:s', $polled)]; // Update this fields //dbUpdate(array('deleted' => '1', 'ifLastChange' => date('Y-m-d H:i:s', $polled)), 'ports', '`device_id` = ? AND `ifIndex` = ?', array($device['device_id'], $port['ifIndex'])); log_event("Interface was marked as DELETED", $device, 'port', $port); } } else { print_message("Port Disabled."); } //echo("\n"); // Clear Per-Port Variables Here unset($this_port); } // MultiUpdate deleted ports if (!safe_empty($ports_db_deleted)) { print_debug("MultiUpdate deleted ports DB."); // MultiUpdate required all UNIQUE keys! dbUpdateMulti($ports_db_deleted, 'ports', ['deleted', 'ifLastChange']); } // MultiUpdate ports state if (!safe_empty($ports_db_state)) { print_debug("MultiUpdate ports states DB."); // MultiUpdate required all UNIQUE keys! dbUpdateMulti($ports_db_state, 'ports'); // Better to pass keys need to update, but without also normal //$columns = array_diff(array_keys($port['state']), array_keys($this_port_indexes)); //dbUpdateMulti($ports_db_state, 'ports', $columns); } $headers = ['%WifIndex%n', '%WLabel%n', '%WType%n', '%WSpeed%n', '%WBPS In%n', '%WBPS Out%n', '%WData In%n', '%WData Out%n', '%WPPS In%n', '%WPPS Out%n', '%WHC%n']; print_cli_table($table_rows, $headers); echo(PHP_EOL); // Clear Variables Here unset($port_stats, $process_port_functions, $process_port_db, $has_ifEntry, $has_ifXEntry, $has_ifEntry_error_code, $ports_ignored_count, $ports_ignored_count_db); // EOF