From 79eab54fd98fd93a89fd4b0202734109e4e73f9d Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Wed, 3 Feb 2016 20:40:05 +0100 Subject: [PATCH 1/5] Allow ignoring unmapable interfaces in poller. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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(). Signed-off-by: Maximilian Wilhelm --- includes/defaults.inc.php | 3 +++ includes/polling/ports.inc.php | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) 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/ports.inc.php b/includes/polling/ports.inc.php index 553069110..03bf4693d 100644 --- a/includes/polling/ports.inc.php +++ b/includes/polling/ports.inc.php @@ -238,6 +238,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)); From 5521002b379bb831080d4db1ceb2af971421d946 Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Wed, 3 Feb 2016 21:05:42 +0100 Subject: [PATCH 2/5] Fix port association for adsl, etherlike and poe port information. In 2c9df26bbf22af94c354bcf445b55a56eaece81a I broke the association of ports in the DB and ports just polled via SNMP for the adsl, etherlike and poe submodules and no one noticed. This fixes this issue. Sorry. Signed-off-by: Maximilian Wilhelm --- includes/polling/port-adsl.inc.php | 4 ++-- includes/polling/port-etherlike.inc.php | 6 +++--- includes/polling/port-poe.inc.php | 6 +++--- includes/polling/ports.inc.php | 17 ++++++++++++----- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/includes/polling/port-adsl.inc.php b/includes/polling/port-adsl.inc.php index e3567e26b..901fb6d0b 100644 --- a/includes/polling/port-adsl.inc.php +++ b/includes/polling/port-adsl.inc.php @@ -39,9 +39,9 @@ // adslAturPerfESs.1 = 0 seconds // adslAturPerfValidIntervals.1 = 0 // adslAturPerfInvalidIntervals.1 = 0 -if (isset($port_stats[$port_id]['adslLineCoding'])) { +if (isset($port_stats[$ifIndex]['adslLineCoding'])) { // Check to make sure Port data is cached. - $this_port = &$port_stats[$port_id]; + $this_port = &$port_stats[$ifIndex]; $rrdfile = get_port_rrdfile_path ($device['hostname'], $port_id, 'adsl'); diff --git a/includes/polling/port-etherlike.inc.php b/includes/polling/port-etherlike.inc.php index bf947b92d..ea8b044c2 100644 --- a/includes/polling/port-etherlike.inc.php +++ b/includes/polling/port-etherlike.inc.php @@ -1,10 +1,10 @@ $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; } // Port vanished (mark as deleted) @@ -299,11 +305,12 @@ 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') { + echo 'Port ' . $port['ifName'] . ': ' . $port['ifDescr'] . '(' . $ifIndex . ') '; + if ($port_stats[$ifIndex] && $port['disabled'] != '1') { // 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]; From ec5d0dfd89e23eced28ffe0cbecb400ab9e25eb5 Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Wed, 3 Feb 2016 21:12:46 +0100 Subject: [PATCH 3/5] Remove redundant code from port-{adsl,etherlike,poe} polling submodules. $this_port already gets defined within include/polling/ports.inc.php so there's no need to redefine it again in each submodule. Signed-off-by: Maximilian Wilhelm --- includes/polling/port-adsl.inc.php | 5 +---- includes/polling/port-etherlike.inc.php | 7 +------ includes/polling/port-poe.inc.php | 7 +------ 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/includes/polling/port-adsl.inc.php b/includes/polling/port-adsl.inc.php index 901fb6d0b..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[$ifIndex]['adslLineCoding'])) { - // Check to make sure Port data is cached. - $this_port = &$port_stats[$ifIndex]; - +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 ea8b044c2..729990162 100644 --- a/includes/polling/port-etherlike.inc.php +++ b/includes/polling/port-etherlike.inc.php @@ -1,11 +1,6 @@ Date: Wed, 3 Feb 2016 22:48:18 +0100 Subject: [PATCH 4/5] Fix detection of deleted interfaces for ifName/ifDescr port association mode. The previous ifIndex based port mapping schema did detect deleted ports by checking ports in the DB against the ports currently polled via SNMP which breaks when using another port mapping schema. This commit fixes problem by checking known and found ports by their port_id. Signed-off-by: Maximilian Wilhelm --- includes/polling/ports.inc.php | 40 +++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/includes/polling/ports.inc.php b/includes/polling/ports.inc.php index 6a4606861..3bbcf5ff3 100644 --- a/includes/polling/ports.inc.php +++ b/includes/polling/ports.inc.php @@ -224,6 +224,7 @@ foreach ($ports_mapped['maps']['ifIndex'] as $ifIndex => $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 @@ -289,6 +290,9 @@ foreach ($port_stats as $ifIndex => $port) { */ $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) @@ -307,8 +311,28 @@ foreach ($ports as $port) { $port_id = $port['port_id']; $ifIndex = $port['ifIndex']; - echo 'Port ' . $port['ifName'] . ': ' . $port['ifDescr'] . '(' . $ifIndex . ') '; - if ($port_stats[$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[$ifIndex]; @@ -654,19 +678,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"; @@ -676,3 +689,4 @@ foreach ($ports as $port) { // Clear Variables Here unset($port_stats); +unset($ports_found); From 6ef1cf9e43a3c7a50f6831fb51a73e844321eccc Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Fri, 5 Feb 2016 11:40:37 +0100 Subject: [PATCH 5/5] Add ability to map ports based on their ifAlias. Signed-off-by: Maximilian Wilhelm --- includes/common.php | 2 +- sql-schema/099.sql | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 sql-schema/099.sql diff --git a/includes/common.php b/includes/common.php index d74a512a9..943feb930 100644 --- a/includes/common.php +++ b/includes/common.php @@ -1248,7 +1248,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/sql-schema/099.sql b/sql-schema/099.sql new file mode 100644 index 000000000..646e4c4e1 --- /dev/null +++ b/sql-schema/099.sql @@ -0,0 +1 @@ +INSERT INTO port_association_mode (name) values ('ifAlias');