diff --git a/includes/common.php b/includes/common.php index 04c681aaf..8b59ba774 100644 --- a/includes/common.php +++ b/includes/common.php @@ -1249,7 +1249,7 @@ function get_port_id ($ports_mapped, $port, $port_association_mode) { */ $maps = $ports_mapped['maps']; - if (in_array ($port_association_mode, array ('ifIndex', 'ifName', 'ifDescr'))) { + if (in_array ($port_association_mode, array ('ifIndex', 'ifName', 'ifDescr', 'ifAlias'))) { $port_id = $maps[$port_association_mode][$port[$port_association_mode]]; } diff --git a/includes/defaults.inc.php b/includes/defaults.inc.php index 8dfa46c8d..bed0b577d 100644 --- a/includes/defaults.inc.php +++ b/includes/defaults.inc.php @@ -858,3 +858,6 @@ $config['update_channel'] = 'master'; // Default port association mode $config['default_port_association_mode'] = 'ifIndex'; +// Ignore ports which can't be mapped using a devices port_association_mode +// See include/polling/ports.inc.php for a lenghty explanation. +$config['ignore_unmapable_port'] = False; diff --git a/includes/polling/port-adsl.inc.php b/includes/polling/port-adsl.inc.php index e3567e26b..42b986428 100644 --- a/includes/polling/port-adsl.inc.php +++ b/includes/polling/port-adsl.inc.php @@ -39,10 +39,7 @@ // adslAturPerfESs.1 = 0 seconds // adslAturPerfValidIntervals.1 = 0 // adslAturPerfInvalidIntervals.1 = 0 -if (isset($port_stats[$port_id]['adslLineCoding'])) { - // Check to make sure Port data is cached. - $this_port = &$port_stats[$port_id]; - +if (isset($this_port['adslLineCoding'])) { $rrdfile = get_port_rrdfile_path ($device['hostname'], $port_id, 'adsl'); $rrd_create = ' --step 300'; diff --git a/includes/polling/port-etherlike.inc.php b/includes/polling/port-etherlike.inc.php index bf947b92d..729990162 100644 --- a/includes/polling/port-etherlike.inc.php +++ b/includes/polling/port-etherlike.inc.php @@ -1,11 +1,6 @@ $port_id) { } +$ports_found = array (); // New interface detection foreach ($port_stats as $ifIndex => $port) { // Store ifIndex in port entry and prefetch ifName as we'll need it multiple times @@ -238,6 +239,31 @@ foreach ($port_stats as $ifIndex => $port) { // Port newly discovered? if (! $ports[$port_id]) { + /** + * When using the ifName or ifDescr as means to map discovered ports to + * known ports in the DB (think of port association mode) it's possible + * that we're facing the problem that the ifName or ifDescr polled from + * the device is unset or an empty string (like when querying some ubnt + * devices...). If this happends we have no way to map this port to any + * port found in the database. As reported this situation may occur for + * the time of one poll and might resolve automagically before the next + * poller run happens. Without this special case this would lead to new + * ports added to the database each time this situation occurs. To give + * the user the choice between »a lot of new ports« and »some poll runs + * are missed but ports stay stable« the 'ignore_unmapable_port' option + * has been added to configure this behaviour. To skip the port in this + * loop is sufficient as the next loop is looping only over ports found + * in the database and "maps back". As we did not add a new port to the + * DB here, there's no port to be mapped to. + * + * I'm using the in_array() check here, as I'm not sure if an "ifIndex" + * can be legally set to 0, which would yield True when checking if the + * value is empty(). + */ + if ($config['ignore_unmapable_port'] === True and in_array ($port[$port_association_mode], array ('', Null))) { + continue; + } + $port_id = dbInsert(array('device_id' => $device['device_id'], 'ifIndex' => $ifIndex, 'ifName' => $ifName), 'ports'); dbInsert(array('port_id' => $port_id), 'ports_statistics'); $ports[$port_id] = dbFetchRow('SELECT * FROM `ports` WHERE `port_id` = ?', array($port_id)); @@ -255,9 +281,18 @@ foreach ($port_stats as $ifIndex => $port) { dbInsert(array('port_id' => $port_id), 'ports_statistics'); } - // Assure stable mapping - $port_stats[$ifIndex]['port_id'] = $port_id; + /** Assure stable bidirectional port mapping between DB and polled data + * + * Store the *current* ifIndex in the port info array containing all port information + * fetched from the database, as this is the only means we have to map ports_stats we + * just polled from the device to a port in $ports. All code below an includeed below + * will and has to map a port using it's ifIndex. + */ $ports[$port_id]['ifIndex'] = $ifIndex; + $port_stats[$ifIndex]['port_id'] = $port_id; + + /* Build a list of all ports, identified by their port_id, found within this poller run. */ + $ports_found[] = $port_id; } // Port vanished (mark as deleted) @@ -274,11 +309,32 @@ echo "\n"; // Loop ports in the DB and update where necessary foreach ($ports as $port) { $port_id = $port['port_id']; + $ifIndex = $port['ifIndex']; - echo 'Port ' . $port['ifName'] . ': ' . $port['ifDescr'] . '(' . $port['ifIndex'] . ') '; - if ($port_stats[$port['ifIndex']] && $port['disabled'] != '1') { + $port_info_string = 'Port ' . $port['ifName'] . ': ' . $port['ifDescr'] . " ($ifIndex / #$port_id) "; + + /* We don't care for disabled ports, go on */ + if ($port['disabled'] == 1) { + echo "$port_info_string disabled.\n"; + continue; + } + + /** + * If this port did not show up in $port_stats before it has been deleted + * since the last poller run. Mark it deleted in the database and go on. + */ + if (! in_array ($port_id, $ports_found)) { + if ($port['deleted'] != '1') { + dbUpdate(array('deleted' => '1'), 'ports', '`device_id` = ? AND `port_id` = ?', array($device['device_id'], $port_id)); + echo "$port_info_string deleted.\n"; + } + continue; + } + + echo $port_info_string; + if ($port_stats[$ifIndex]) { // Check to make sure Port data is cached. - $this_port = &$port_stats[$port['ifIndex']]; + $this_port = &$port_stats[$ifIndex]; if ($device['os'] == 'vmware' && preg_match('/Device ([a-z0-9]+) at .*/', $this_port['ifDescr'], $matches)) { $this_port['ifDescr'] = $matches[1]; @@ -625,19 +681,8 @@ foreach ($ports as $port) { $updated += dbUpdate($port['update_extended'], 'ports_statistics', '`port_id` = ?', array($port_id)); d_echo("$updated updated"); } - // End Update Database } - else if ($port['disabled'] != '1') { - echo 'Port Deleted'; - // Port missing from SNMP cache. - if ($port['deleted'] != '1') { - dbUpdate(array('deleted' => '1'), 'ports', '`device_id` = ? AND `port_id` = ?', array($device['device_id'], $port_id)); - } - } - else { - echo 'Port Disabled.'; - }//end if echo "\n"; @@ -647,3 +692,4 @@ foreach ($ports as $port) { // Clear Variables Here unset($port_stats); +unset($ports_found); diff --git a/sql-schema/100.sql b/sql-schema/100.sql new file mode 100644 index 000000000..646e4c4e1 --- /dev/null +++ b/sql-schema/100.sql @@ -0,0 +1 @@ +INSERT INTO port_association_mode (name) values ('ifAlias');