diff --git a/addhost.php b/addhost.php index 2280c54e3..381c602da 100755 --- a/addhost.php +++ b/addhost.php @@ -19,7 +19,7 @@ require 'config.php'; require 'includes/definitions.inc.php'; require 'includes/functions.php'; -$options = getopt('g:f::'); +$options = getopt('g:p:f::'); if (isset($options['g']) && $options['g'] >= 0) { $cmd = array_shift($argv); @@ -39,6 +39,22 @@ if (isset($options['f']) && $options['f'] == 0) { $force_add = 1; } +$port_assoc_mode = $config['default_port_association_mode']; +$valid_assoc_modes = get_port_assoc_modes (); +if (isset ($options['p'])) { + $port_assoc_mode = $options['p']; + if (! in_array ($port_assoc_mode, $valid_assoc_modes)) { + echo "Invalid port association mode '" . $port_assoc_mode . "'\n"; + echo 'Valid modes: ' . join (', ', $valid_assoc_modes) . "\n"; + exit; + } + + $cmd = array_shift($argv); + array_shift($argv); + array_shift($argv); + array_unshift($argv, $cmd); +} + if (!empty($argv[1])) { $host = strtolower($argv[1]); $community = $argv[2]; @@ -82,7 +98,7 @@ if (!empty($argv[1])) { array_push($config['snmp']['v3'], $v3); } - $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add); + $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add, $port_assoc_mode); } else if ($seclevel === 'anp' or $seclevel === 'authNoPriv') { $v3['authlevel'] = 'authNoPriv'; @@ -108,7 +124,7 @@ if (!empty($argv[1])) { } array_push($config['snmp']['v3'], $v3); - $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add); + $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add, $port_assoc_mode); } else if ($seclevel === 'ap' or $seclevel === 'authPriv') { $v3['authlevel'] = 'authPriv'; @@ -138,7 +154,7 @@ if (!empty($argv[1])) { }//end while array_push($config['snmp']['v3'], $v3); - $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add); + $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add, $port_assoc_mode); } else { // Error or do nothing ? @@ -164,7 +180,7 @@ if (!empty($argv[1])) { $config['snmp']['community'] = array($community); } - $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add); + $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add, $port_assoc_mode); }//end if if ($snmpver) { @@ -180,7 +196,7 @@ if (!empty($argv[1])) { while (!$device_id && count($snmpversions)) { $snmpver = array_shift($snmpversions); - $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add); + $device_id = addHost($host, $snmpver, $port, $transport, 0, $poller_group, $force_add, $port_assoc_mode); } if ($device_id) { @@ -193,14 +209,18 @@ if (!empty($argv[1])) { print $console_color->convert( "\n".$config['project_name_version'].' Add Host Tool - Usage (SNMPv1/2c): ./addhost.php [-g ] [-f] <%Whostname%n> [community] [v1|v2c] [port] ['.implode('|', $config['snmp']['transports']).'] - Usage (SNMPv3) : Config Defaults : ./addhost.php [-g ] [-f]<%Whostname%n> any v3 [user] [port] ['.implode('|', $config['snmp']['transports']).'] - No Auth, No Priv : ./addhost.php [-g ] [-f]<%Whostname%n> nanp v3 [user] [port] ['.implode('|', $config['snmp']['transports']).'] - Auth, No Priv : ./addhost.php [-g ] [-f]<%Whostname%n> anp v3 [md5|sha] [port] ['.implode('|', $config['snmp']['transports']).'] - Auth, Priv : ./addhost.php [-g ] [-f]<%Whostname%n> ap v3 [md5|sha] [aes|dsa] [port] ['.implode('|', $config['snmp']['transports']).'] + Usage (SNMPv1/2c): ./addhost.php [-g ] [-f] [-p ] <%Whostname%n> [community] [v1|v2c] [port] ['.implode('|', $config['snmp']['transports']).'] + Usage (SNMPv3) : Config Defaults : ./addhost.php [-g ] [-f] [-p ] <%Whostname%n> any v3 [user] [port] ['.implode('|', $config['snmp']['transports']).'] + No Auth, No Priv : ./addhost.php [-g ] [-f] [-p ] <%Whostname%n> nanp v3 [user] [port] ['.implode('|', $config['snmp']['transports']).'] + Auth, No Priv : ./addhost.php [-g ] [-f] [-p ] <%Whostname%n> anp v3 [md5|sha] [port] ['.implode('|', $config['snmp']['transports']).'] + Auth, Priv : ./addhost.php [-g ] [-f] [-p ] <%Whostname%n> ap v3 [md5|sha] [aes|dsa] [port] ['.implode('|', $config['snmp']['transports']).'] -g allows you to add a device to be pinned to a specific poller when using distributed polling. X can be any number associated with a poller group -f forces the device to be added by skipping the icmp and snmp check against the host. + -p allow you to set a port association mode for this device. By default ports are associated by \'ifIndex\'. + For Linux/Unix based devices \'ifName\' or \'ifDescr\' might be useful for a stable iface mapping. + The default for this installation is \'' . $config['default_port_association_mode'] . '\' + Valid port assoc modes are: ' . join (', ', $valid_assoc_modes) . ' %rRemember to run discovery for the host afterwards.%n ' diff --git a/config.php.default b/config.php.default index f6b031cd7..2da0514e0 100755 --- a/config.php.default +++ b/config.php.default @@ -49,3 +49,6 @@ $config['poller-wrapper']['alerter'] = FALSE; # Uncomment to submit callback stats via proxy #$config['callback_proxy'] = "hostname:port"; + +# Set default port association mode for new devices (default: ifIndex) +#$config['default_port_association_mode'] = 'ifIndex'; diff --git a/html/includes/graphs/bill/bits.inc.php b/html/includes/graphs/bill/bits.inc.php index 2e80ef792..266fa86a2 100644 --- a/html/includes/graphs/bill/bits.inc.php +++ b/html/includes/graphs/bill/bits.inc.php @@ -4,8 +4,9 @@ $i = 0; foreach ($ports as $port) { - if (is_file($config['rrd_dir'].'/'.$port['hostname'].'/port-'.safename($port['ifIndex'].'.rrd'))) { - $rrd_list[$i]['filename'] = $config['rrd_dir'].'/'.$port['hostname'].'/port-'.safename($port['ifIndex'].'.rrd'); + $rrd_file = get_port_rrdfile_path ($port['hostname'], $port['port_id']); + if (is_file($rrd_file)) { + $rrd_list[$i]['filename'] = $rrd_file; $rrd_list[$i]['descr'] = $port['ifDescr']; $i++; } diff --git a/html/includes/graphs/customer/bits.inc.php b/html/includes/graphs/customer/bits.inc.php index f66f91df0..ee3d4a741 100644 --- a/html/includes/graphs/customer/bits.inc.php +++ b/html/includes/graphs/customer/bits.inc.php @@ -10,8 +10,8 @@ if (!is_array($config['customers_descr'])) { $descr_type = "'".implode("', '", $config['customers_descr'])."'"; foreach (dbFetchRows('SELECT * FROM `ports` AS I, `devices` AS D WHERE `port_descr_type` IN (?) AND `port_descr_descr` = ? AND D.device_id = I.device_id', array(array($descr_type), $vars['id'])) as $port) { - if (is_file($config['rrd_dir'].'/'.$port['hostname'].'/port-'.safename($port['ifIndex'].'.rrd'))) { - $rrd_filename = $config['rrd_dir'].'/'.$port['hostname'].'/port-'.safename($port['ifIndex'].'.rrd'); + $rrd_filename = get_port_rrdfile_path ($port['hostname'], $port['port_id']); // FIXME: Unification OK? + if (is_file($rrd_filename)) { $rrd_list[$i]['filename'] = $rrd_filename; $rrd_list[$i]['descr'] = $port['hostname'].'-'.$port['ifDescr']; $rrd_list[$i]['descr_in'] = shorthost($port['hostname']); @@ -20,7 +20,6 @@ foreach (dbFetchRows('SELECT * FROM `ports` AS I, `devices` AS D WHERE `port_des } } -// echo($config['rrd_dir'] . "/" . $port['hostname'] . "/port-" . safename($port['ifIndex'] . ".rrd")); $units = 'bps'; $total_units = 'B'; $colours_in = 'greens'; diff --git a/html/includes/graphs/device/bits.inc.php b/html/includes/graphs/device/bits.inc.php index eaeed92f4..f796490f2 100644 --- a/html/includes/graphs/device/bits.inc.php +++ b/html/includes/graphs/device/bits.inc.php @@ -22,7 +22,7 @@ foreach (dbFetchRows('SELECT * FROM `ports` WHERE `device_id` = ?', array($devic } } - $rrd_filename = $config['rrd_dir'].'/'.$device['hostname'].'/port-'.safename($port['ifIndex'].'.rrd'); + $rrd_filename = get_port_rrdfile_path ($device['hostname'], $port['port_id']); if ($ignore != 1 && is_file($rrd_filename)) { $port = ifLabel($port); // Fix Labels! ARGH. This needs to be in the bloody database! diff --git a/html/includes/graphs/global/bits.inc.php b/html/includes/graphs/global/bits.inc.php index 763a9d103..350d96f87 100644 --- a/html/includes/graphs/global/bits.inc.php +++ b/html/includes/graphs/global/bits.inc.php @@ -21,7 +21,7 @@ foreach (dbFetchRows('SELECT * FROM `ports` AS P, `devices` AS D WHERE D.device_ } } - $rrd_filename = $config['rrd_dir'].'/'.$port['hostname'].'/port-'.safename($port['ifIndex'].'.rrd'); + $rrd_filename = get_port_rrdfile_path ($port['hostname'], $port['port_id']); if (!$ignore && $i < 1100 && is_file($rrd_filename)) { $rrd_filenames[] = $rrd_filename; $rrd_list[$i]['filename'] = $rrd_filename; diff --git a/html/includes/graphs/location/bits.inc.php b/html/includes/graphs/location/bits.inc.php index 53b0a656e..7f77108a9 100644 --- a/html/includes/graphs/location/bits.inc.php +++ b/html/includes/graphs/location/bits.inc.php @@ -24,8 +24,9 @@ foreach ($devices as $device) { } } - if (is_file($config['rrd_dir'].'/'.$device['hostname'].'/port-'.safename($int['ifIndex'].'.rrd')) && $ignore != 1) { - $rrd_filename = $config['rrd_dir'].'/'.$device['hostname'].'/port-'.safename($int['ifIndex'].'.rrd'); + $rrd_file = get_port_rrdfile_path ($device['hostname'], $int['port_id']); + if (is_file($rrd_file) && $ignore != 1) { + $rrd_filename = $rrd_file; // FIXME: Can this be unified without side-effects? $rrd_list[$i]['filename'] = $rrd_filename; $rrd_list[$i]['descr'] = $port['label']; $rrd_list[$i]['descr_in'] = $device['hostname']; diff --git a/html/includes/graphs/multiport/bits.inc.php b/html/includes/graphs/multiport/bits.inc.php index de3206c23..e64e39b31 100644 --- a/html/includes/graphs/multiport/bits.inc.php +++ b/html/includes/graphs/multiport/bits.inc.php @@ -8,9 +8,10 @@ foreach (explode(',', $vars['id']) as $ifid) { $ifid = str_replace('!', '', $ifid); } - $int = dbFetchRow('SELECT `ifIndex`, `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); - if (is_file($config['rrd_dir'].'/'.$int['hostname'].'/port-'.safename($int['ifIndex'].'.rrd'))) { - $rrd_filenames[$i] = $config['rrd_dir'].'/'.$int['hostname'].'/port-'.safename($int['ifIndex'].'.rrd'); + $int = dbFetchRow('SELECT `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); + $rrd_file = get_port_rrdfile_path ($int['hostname'], $ifid); + if (is_file($rrd_file)) { + $rrd_filenames[$i] = $rrd_file; $i++; } } diff --git a/html/includes/graphs/multiport/bits_duo.inc.php b/html/includes/graphs/multiport/bits_duo.inc.php index 205ca3834..cc9892dde 100644 --- a/html/includes/graphs/multiport/bits_duo.inc.php +++ b/html/includes/graphs/multiport/bits_duo.inc.php @@ -13,10 +13,11 @@ if ($height < '99') { $i = 1; foreach (explode(',', $_GET['id']) as $ifid) { - $int = dbFetchRow('SELECT `ifIndex`, `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); - if (is_file($config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd')) { - $rrd_options .= ' DEF:inoctets'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:INOCTETS:AVERAGE'; - $rrd_options .= ' DEF:outoctets'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:OUTOCTETS:AVERAGE'; + $int = dbFetchRow('SELECT `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); + $rrd_file = get_port_rrdfile_path ($int['hostname'], $ifid); + if (is_file($rrd_file)) { + $rrd_options .= ' DEF:inoctets'.$i.'='.$rrd_file.':INOCTETS:AVERAGE'; + $rrd_options .= ' DEF:outoctets'.$i.'='.$rrd_file.':OUTOCTETS:AVERAGE'; $in_thing .= $seperator.'inoctets'.$i.',UN,0,'.'inoctets'.$i.',IF'; $out_thing .= $seperator.'outoctets'.$i.',UN,0,'.'outoctets'.$i.',IF'; $pluses .= $plus; @@ -30,10 +31,11 @@ unset($seperator); unset($plus); foreach (explode(',', $_GET['idb']) as $ifid) { - $int = dbFetchRow('SELECT `ifIndex`, `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); - if (is_file($config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd')) { - $rrd_options .= ' DEF:inoctetsb'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:INOCTETS:AVERAGE'; - $rrd_options .= ' DEF:outoctetsb'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:OUTOCTETS:AVERAGE'; + $int = dbFetchRow('SELECT `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); + $rrd_file = get_port_rrdfile_path ($int['hostname'], $ifid); + if (is_file($rrd_file)) { + $rrd_options .= ' DEF:inoctetsb'.$i.'='.$rrd_file.':INOCTETS:AVERAGE'; + $rrd_options .= ' DEF:outoctetsb'.$i.'='.$rrd_file.':OUTOCTETS:AVERAGE'; $in_thingb .= $seperator.'inoctetsb'.$i.',UN,0,'.'inoctetsb'.$i.',IF'; $out_thingb .= $seperator.'outoctetsb'.$i.',UN,0,'.'outoctetsb'.$i.',IF'; $plusesb .= $plus; diff --git a/html/includes/graphs/multiport/bits_separate.inc.php b/html/includes/graphs/multiport/bits_separate.inc.php index d54259d02..980386286 100644 --- a/html/includes/graphs/multiport/bits_separate.inc.php +++ b/html/includes/graphs/multiport/bits_separate.inc.php @@ -4,9 +4,10 @@ $i = 0; foreach (explode(',', $vars['id']) as $ifid) { $port = dbFetchRow('SELECT * FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); - if (is_file($config['rrd_dir'].'/'.$port['hostname'].'/port-'.safename($port['ifIndex'].'.rrd'))) { + $rrd_file = get_port_rrdfile_path ($port['hostname'], $ifid); + if (is_file($rrd_file)) { $port = ifLabel($port); - $rrd_list[$i]['filename'] = $config['rrd_dir'].'/'.$port['hostname'].'/port-'.safename($port['ifIndex'].'.rrd'); + $rrd_list[$i]['filename'] = $rrd_file; $rrd_list[$i]['descr'] = $port['hostname'].' '.$port['ifDescr']; $rrd_list[$i]['descr_in'] = $port['hostname']; $rrd_list[$i]['descr_out'] = makeshortif($port['label']); diff --git a/html/includes/graphs/multiport/bits_trio.inc.php b/html/includes/graphs/multiport/bits_trio.inc.php index a1112a677..563ae1b9b 100644 --- a/html/includes/graphs/multiport/bits_trio.inc.php +++ b/html/includes/graphs/multiport/bits_trio.inc.php @@ -14,8 +14,9 @@ if ($height < '99') { $i = 1; foreach (explode(',', $_GET['id']) as $ifid) { - $int = dbFetchRow('SELECT `ifIndex`, `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); - if (is_file($config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd')) { + $int = dbFetchRow('SELECT `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); + $rrd_file = get_port_rrdfile_path ($int['hostname'], $ifid); + if (is_file($rrd_file)) { if (strstr($inverse, 'a')) { $in = 'OUT'; $out = 'IN'; @@ -25,8 +26,8 @@ foreach (explode(',', $_GET['id']) as $ifid) { $out = 'OUT'; } - $rrd_options .= ' DEF:inoctets'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:'.$in.'OCTETS:AVERAGE'; - $rrd_options .= ' DEF:outoctets'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:'.$out.'OCTETS:AVERAGE'; + $rrd_options .= ' DEF:inoctets'.$i.'='.$rrd_file.':'.$in.'OCTETS:AVERAGE'; + $rrd_options .= ' DEF:outoctets'.$i.'='.$rrd_file.':'.$out.'OCTETS:AVERAGE'; $in_thing .= $seperator.'inoctets'.$i.',UN,0,'.'inoctets'.$i.',IF'; $out_thing .= $seperator.'outoctets'.$i.',UN,0,'.'outoctets'.$i.',IF'; $pluses .= $plus; @@ -40,8 +41,9 @@ unset($seperator); unset($plus); foreach (explode(',', $_GET['idb']) as $ifid) { - $int = dbFetchRow('SELECT `ifIndex`, `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); - if (is_file($config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd')) { + $int = dbFetchRow('SELECT `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); + $rrd_file = get_port_rrdfile_path ($int['hostname'], $ifid); + if (is_file($rrd_file)) { if (strstr($inverse, 'b')) { $in = 'OUT'; $out = 'IN'; @@ -51,8 +53,8 @@ foreach (explode(',', $_GET['idb']) as $ifid) { $out = 'OUT'; } - $rrd_options .= ' DEF:inoctetsb'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:'.$in.'OCTETS:AVERAGE'; - $rrd_options .= ' DEF:outoctetsb'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:'.$out.'OCTETS:AVERAGE'; + $rrd_options .= ' DEF:inoctetsb'.$i.'='.$rrd_file.':'.$in.'OCTETS:AVERAGE'; + $rrd_options .= ' DEF:outoctetsb'.$i.'='.$rrd_file.':'.$out.'OCTETS:AVERAGE'; $in_thingb .= $seperator.'inoctetsb'.$i.',UN,0,'.'inoctetsb'.$i.',IF'; $out_thingb .= $seperator.'outoctetsb'.$i.',UN,0,'.'outoctetsb'.$i.',IF'; $plusesb .= $plus; @@ -66,8 +68,9 @@ unset($seperator); unset($plus); foreach (explode(',', $_GET['idc']) as $ifid) { - $int = dbFetchRow('SELECT `ifIndex`, `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); - if (is_file($config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd')) { + $int = dbFetchRow('SELECT `hostname` FROM `ports` AS I, devices as D WHERE I.port_id = ? AND I.device_id = D.device_id', array($ifid)); + $rrd_file = get_port_rrdfile_path ($int['hostname'], $ifid); + if (is_file($rrd_file)) { if (strstr($inverse, 'c')) { $in = 'OUT'; $out = 'IN'; @@ -77,8 +80,8 @@ foreach (explode(',', $_GET['idc']) as $ifid) { $out = 'OUT'; } - $rrd_options .= ' DEF:inoctetsc'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:'.$in.'OCTETS:AVERAGE'; - $rrd_options .= ' DEF:outoctetsc'.$i.'='.$config['rrd_dir'].'/'.$int['hostname'].'/port-'.$int['ifIndex'].'.rrd:'.$out.'OCTETS:AVERAGE'; + $rrd_options .= ' DEF:inoctetsc'.$i.'='.$rrd_file.':'.$in.'OCTETS:AVERAGE'; + $rrd_options .= ' DEF:outoctetsc'.$i.'='.$rrd_file.':'.$out.'OCTETS:AVERAGE'; $in_thingc .= $seperator.'inoctetsc'.$i.',UN,0,'.'inoctetsc'.$i.',IF'; $out_thingc .= $seperator.'outoctetsc'.$i.',UN,0,'.'outoctetsc'.$i.',IF'; $plusesc .= $plus; diff --git a/html/includes/graphs/port/adsl_attainable.inc.php b/html/includes/graphs/port/adsl_attainable.inc.php index ad84314a0..7f2e2f33a 100644 --- a/html/includes/graphs/port/adsl_attainable.inc.php +++ b/html/includes/graphs/port/adsl_attainable.inc.php @@ -1,6 +1,6 @@ '; // If we're showing graphs, generate the graph and print the img tags if ($graph_type == 'etherlike') { - $graph_file = $config['rrd_dir'].'/'.$device['hostname'].'/port-'.safename($port['ifIndex']).'-dot3.rrd'; + $graph_file = get_port_rrdfile_path ($device['hostname'], $if_id, 'dot3'); } else { - $graph_file = $config['rrd_dir'].'/'.$device['hostname'].'/port-'.safename($port['ifIndex']).'.rrd'; + $graph_file = get_port_rrdfile_path ($device['hostname'], $if_id); } if ($graph_type && is_file($graph_file)) { diff --git a/html/pages/addhost.inc.php b/html/pages/addhost.inc.php index 2844982d7..fdbf9b0e3 100644 --- a/html/pages/addhost.inc.php +++ b/html/pages/addhost.inc.php @@ -65,7 +65,8 @@ if ($_POST['hostname']) { $force_add = 0; } - $result = addHost($hostname, $snmpver, $port, $transport, 0, $poller_group, $force_add); + $port_assoc_mode = $_POST['port_assoc_mode']; + $result = addHost($hostname, $snmpver, $port, $transport, 0, $poller_group, $force_add, $port_assoc_mode); if ($result) { print_message("Device added ($result)"); } @@ -120,6 +121,24 @@ foreach ($config['snmp']['transports'] as $transport) { echo '>'.$transport.''; } +?> + + + +
+ +
+
diff --git a/html/pages/device/edit/snmp.inc.php b/html/pages/device/edit/snmp.inc.php index cf2054cfc..b77f3dcc4 100644 --- a/html/pages/device/edit/snmp.inc.php +++ b/html/pages/device/edit/snmp.inc.php @@ -9,6 +9,7 @@ if ($_POST['editing']) { $timeout = mres($_POST['timeout']); $retries = mres($_POST['retries']); $poller_group = mres($_POST['poller_group']); + $port_assoc_mode = mres($_POST['port_assoc_mode']); $v3 = array( 'authlevel' => mres($_POST['authlevel']), 'authname' => mres($_POST['authname']), @@ -25,6 +26,7 @@ if ($_POST['editing']) { 'port' => $port, 'transport' => $transport, 'poller_group' => $poller_group, + 'port_association_mode' => $port_assoc_mode, ); if ($_POST['timeout']) { @@ -43,7 +45,7 @@ if ($_POST['editing']) { $update = array_merge($update, $v3); - $device_tmp = deviceArray($device['hostname'], $community, $snmpver, $port, $transport, $v3); + $device_tmp = deviceArray($device['hostname'], $community, $snmpver, $port, $transport, $v3, $port_assoc_mode); if (isSNMPable($device_tmp)) { $rows_updated = dbUpdate($update, 'devices', '`device_id` = ?', array($device['device_id'])); @@ -116,6 +118,25 @@ echo "
+
+ +
+ +
+
diff --git a/html/pages/device/port/adsl.inc.php b/html/pages/device/port/adsl.inc.php index 170f2a2c5..b9230ccfb 100644 --- a/html/pages/device/port/adsl.inc.php +++ b/html/pages/device/port/adsl.inc.php @@ -1,6 +1,6 @@ ADSL Line Speed
'; $graph_type = 'port_adsl_speed'; diff --git a/html/pages/device/port/graphs.inc.php b/html/pages/device/port/graphs.inc.php index e56f24bf3..64fdde60a 100644 --- a/html/pages/device/port/graphs.inc.php +++ b/html/pages/device/port/graphs.inc.php @@ -1,6 +1,6 @@
@@ -41,7 +41,7 @@ if (file_exists($config['rrd_dir'].'/'.$device['hostname'].'/port-'.$port['ifInd include 'includes/print-interface-graphs.inc.php'; echo '
'; - if (is_file($config['rrd_dir'].'/'.$device['hostname'].'/port-'.$port['ifIndex'].'-dot3.rrd')) { + if (is_file(get_port_rrdfile_path ($device['hostname'], $port['port_id'], 'dot3'))) { echo '

Ethernet Errors

diff --git a/html/pages/iftype.inc.php b/html/pages/iftype.inc.php index 05cfa2217..266b98fb6 100644 --- a/html/pages/iftype.inc.php +++ b/html/pages/iftype.inc.php @@ -94,7 +94,7 @@ if ($if_list) { echo '
'; - if (file_exists($config['rrd_dir'].'/'.$port['hostname'].'/port-'.$port['ifIndex'].'.rrd')) { + if (file_exists(get_port_rrdfile_path ($port['hostname'], $port['port_id']))) { $graph_type = 'port_bits'; include 'includes/print-interface-graphs.inc.php'; diff --git a/includes/common.php b/includes/common.php index d32f836ab..0cbb6b007 100644 --- a/includes/common.php +++ b/includes/common.php @@ -114,7 +114,7 @@ function delete_port($int_id) { dbDelete('links', "`remote_port_id` = ?", array($int_id)); dbDelete('bill_ports', "`port_id` = ?", array($int_id)); - unlink(trim($config['rrd_dir'])."/".trim($interface['hostname'])."/port-".$interface['ifIndex'].".rrd"); + unlink(get_port_rrdfile_path ($interface['hostname'], $interface['port_id'])); } function sgn($int) { @@ -143,6 +143,15 @@ function get_sensor_rrd($device, $sensor) { return($rrd_file); } +function get_port_rrdfile_path ($hostname, $port_id, $suffix = '') { + global $config; + + if (! empty ($suffix)) + $suffix = '-' . $suffix; + + return trim ($config['rrd_dir']) . '/' . safename ($hostname) . '/' . 'port-id' . safename($port_id) . safename ($suffix) . '.rrd'; +} + function get_port_by_index_cache($device_id, $ifIndex) { global $port_index_cache; @@ -1093,3 +1102,155 @@ function ip_to_sysname($device,$ip) { } return $ip; }//end ip_to_sysname + +/** + * Return valid port association modes + * @param bool $no_cache No-Cache flag (optional, default false) + * @return array + */ +function get_port_assoc_modes ($no_cache = false) { + global $config; + + if ($config['memcached']['enable'] && $no_cache === false) { + $assoc_modes = $config['memcached']['resource']->get (hash ('sha512', "port_assoc_modes")); + if (! empty ($assoc_modes)) + return $assoc_modes; + } + + $assoc_modes = Null; + foreach (dbFetchRows ("SELECT `name` FROM `port_association_mode` ORDER BY pom_id") as $row) + $assoc_modes[] = $row['name']; + + if ($config['memcached']['enable'] && $no_cache === false) + $config['memcached']['resource']->set (hash ('sha512', "port_assoc_modes"), $assoc_modes, $config['memcached']['ttl']); + + return $assoc_modes; +} + +/** + * Validate port_association_mode + * @param string $port_assoc_mode + * @return bool + */ +function is_valid_port_assoc_mode ($port_assoc_mode) { + return in_array ($port_assoc_mode, get_port_assoc_modes ()); +} + +/** + * Get DB id of given port association mode name + * @param string $port_assoc_mode + * @param bool $no_cache No-Cache flag (optional, default false) + */ +function get_port_assoc_mode_id ($port_assoc_mode, $no_cache = false) { + global $config; + + if ($config['memcached']['enable'] && $no_cache === false) { + $id = $config['memcached']['resource']->get (hash ('sha512', "port_assoc_mode_id|$port_assoc_mode")); + if (! empty ($id)) + return $id; + } + + $id = Null; + $row = dbFetchRow ("SELECT `pom_id` FROM `port_association_mode` WHERE name = ?", array ($port_assoc_mode)); + if ($row) { + $id = $row['pom_id']; + if ($config['memcached']['enable'] && $no_cache === false) + $config['memcached']['resource']->set (hash ('sha512', "port_assoc_mode_id|$port_assoc_mode"), $id, $config['memcached']['ttl']); + } + + return $id; +} + +/** + * Get name of given port association_mode ID + * @param int $port_assoc_mode_id Port association mode ID + * @param bool $no_cache No-Cache flag (optional, default false) + * @return bool + */ +function get_port_assoc_mode_name ($port_assoc_mode_id, $no_cache = false) { + global $config; + + if ($config['memcached']['enable'] && $no_cache === false) { + $name = $config['memcached']['resource']->get (hash ('sha512', "port_assoc_mode_name|$port_assoc_mode_id")); + if (! empty ($name)) + return $name; + } + + $name = Null; + $row = dbFetchRow ("SELECT `name` FROM `port_association_mode` WHERE pom_id = ?", array ($port_assoc_mode_id)); + if ($row) { + $name = $row['name']; + if ($config['memcached']['enable'] && $no_cache === false) + $config['memcached']['resource']->set (hash ('sha512', "port_assoc_mode_name|$port_assoc_mode_id"), $name, $config['memcached']['ttl']); + } + + return $name; +} + +/** + * Query all ports of the given device (by ID) and build port array and + * port association maps for ifIndex, ifName, ifDescr. Query port stats + * if told to do so, too. + * @param int $device_id ID of device to query ports for + * @param bool $with_statistics Query port statistics, too. (optional, default false) + * @return array + */ +function get_ports_mapped ($device_id, $with_statistics = false) { + $ports = []; + $maps = [ + 'ifIndex' => [], + 'ifName' => [], + 'ifDescr' => [], + ]; + + /* Query all information available for ports for this device ... */ + $query = 'SELECT * FROM `ports` WHERE `device_id` = ? ORDER BY port_id'; + if ($with_statistics) { + /* ... including any related ports_statistics if requested */ + $query = 'SELECT *, `ports_statistics`.`port_id` AS `ports_statistics_port_id`, `ports`.`port_id` AS `port_id` FROM `ports` LEFT OUTER JOIN `ports_statistics` ON `ports`.`port_id` = `ports_statistics`.`port_id` WHERE `ports`.`device_id` = ? ORDER BY ports.port_id'; + } + + // Query known ports in order of discovery to make sure the latest + // discoverd/polled port is in the mapping tables. + foreach (dbFetchRows ($query, array ($device_id)) as $port) { + // Store port information by ports port_id from DB + $ports[$port['port_id']] = $port; + + // Build maps from ifIndex, ifName, ifDescr to port_id + $maps['ifIndex'][$port['ifIndex']] = $port['port_id']; + $maps['ifName'][$port['ifName']] = $port['port_id']; + $maps['ifDescr'][$port['ifDescr']] = $port['port_id']; + } + + return [ + 'ports' => $ports, + 'maps' => $maps, + ]; +} + +/** + * Calculate port_id of given port using given devices port information and port association mode + * @param array $ports_mapped Port information of device queried by get_ports_mapped() + * @param array $port Port information as fetched from DB + * @param string $port_association_mode Port association mode to use for mapping + * @return int port_id (or Null) + */ +function get_port_id ($ports_mapped, $port, $port_association_mode) { + // Get port_id according to port_association_mode used for this device + $port_id = Null; + + /* + * Information an all ports is available through $ports_mapped['ports'] + * This might come in handy sometime in the future to add you nifty new + * port mapping schema: + * + * $ports = $ports_mapped['ports']; + */ + $maps = $ports_mapped['maps']; + + if (in_array ($port_association_mode, array ('ifIndex', 'ifName', 'ifDescr'))) { + $port_id = $maps[$port_association_mode][$port[$port_association_mode]]; + } + + return $port_id; +} diff --git a/includes/defaults.inc.php b/includes/defaults.inc.php index dff8f976d..8dfa46c8d 100644 --- a/includes/defaults.inc.php +++ b/includes/defaults.inc.php @@ -855,3 +855,6 @@ $config['notifications']['local'] = 'misc/notifications.rs // Update channel (Can be 'master' or 'release') $config['update_channel'] = 'master'; + +// Default port association mode +$config['default_port_association_mode'] = 'ifIndex'; diff --git a/includes/discovery/ports.inc.php b/includes/discovery/ports.inc.php index 32067fa05..c682fa6e5 100644 --- a/includes/discovery/ports.inc.php +++ b/includes/discovery/ports.inc.php @@ -9,27 +9,61 @@ $port_stats = snmpwalk_cache_oid($device, 'ifType', $port_stats, 'IF-MIB'); // End Building SNMP Cache Array d_echo($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); ? -foreach (dbFetchRows('SELECT * FROM `ports` WHERE `device_id` = ?', array($device['device_id'])) as $port) { - $ports_db[$port['ifIndex']] = $port; - $ports_db_l[$port['ifIndex']] = $port['port_id']; + +// By default libreNMS uses the ifIndex to associate ports on devices with ports discoverd/polled +// before and stored in the database. On Linux boxes this is a problem as ifIndexes may be +// unstable between reboots or (re)configuration of tunnel interfaces (think: GRE/OpenVPN/Tinc/...) +// The port association configuration allows to choose between association via ifIndex, ifName, +// or maybe other means in the future. The default port association mode still is ifIndex for +// compatibility reasons. +$port_association_mode = $config['default_port_association_mode']; +if ($device['port_association_mode']) + $port_association_mode = get_port_assoc_mode_name ($device['port_association_mode']); + +// Build array of ports in the database and an ifIndex/ifName -> port_id map +$ports_mapped = get_ports_mapped ($device['id']); +$ports_db = $ports_mapped['ports']; + +// +// Rename any old RRD files still named after the previous ifIndex based naming schema. +foreach ($ports_mapped['maps']['ifIndex'] as $ifIndex => $port_id) { + foreach (array ('', 'adsl', 'dot3') as $suffix) { + $suffix_tmp = ''; + if ($suffix) + $suffix_tmp = "-$suffix"; + + $old_rrd_path = trim ($config['rrd_dir']) . '/' . $device['hostname'] . "/port-$ifIndex$suffix_tmp.rrd"; + $new_rrd_path = get_port_rrdfile_path ($device['hostname'], $port_id, $suffix); + + if (is_file ($old_rrd_path)) { + rename ($old_rrd_path, $new_rrd_path); + } + } } + // New interface detection foreach ($port_stats as $ifIndex => $port) { - // Check the port against our filters. + // Store ifIndex in port entry and prefetch ifName as we'll need it multiple times + $port['ifIndex'] = $ifIndex; + $ifName = $port['ifName']; + + // Get port_id according to port_association_mode used for this device + $port_id = get_port_id ($ports_mapped, $port, $port_association_mode); + if (is_port_valid($port, $device)) { - if (!is_array($ports_db[$ifIndex])) { - $port_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']]['port_id'].')'; + + // Port newly discovered? + if (! is_array($ports_db[$port_id])) { + $port_id = dbInsert(array('device_id' => $device['device_id'], 'ifIndex' => $ifIndex, 'ifName' => $ifName), 'ports'); + $ports[$port_id] = dbFetchRow('SELECT * FROM `ports` WHERE `device_id` = ? AND `port_id` = ?', array($device['device_id'], $port_id)); + echo 'Adding: '.$ifName.'('.$ifIndex.')('.$port_id.')'; } - else if ($ports_db[$ifIndex]['deleted'] == '1') { - dbUpdate(array('deleted' => '0'), 'ports', '`port_id` = ?', array($ports_db[$ifIndex]['port_id'])); - $ports_db[$ifIndex]['deleted'] = '0'; + + // Port re-discovered after previous deletion? + else if ($ports_db[$port_id]['deleted'] == '1') { + dbUpdate(array('deleted' => '0'), 'ports', '`port_id` = ?', array($ports_db[$port_id])); + $ports_db[$port_id]['deleted'] = '0'; echo 'U'; } else { @@ -39,11 +73,13 @@ foreach ($port_stats as $ifIndex => $port) { // We've seen it. Remove it from the cache. unset($ports_l[$ifIndex]); } + + // Port vanished (mark as deleted) else { - if (is_array($ports_db[$port['ifIndex']])) { - if ($ports_db[$port['ifIndex']]['deleted'] != '1') { - dbUpdate(array('deleted' => '1'), 'ports', '`port_id` = ?', array($ports_db[$ifIndex]['port_id'])); - $ports_db[$ifIndex]['deleted'] = '1'; + if (is_array($ports_db[$port_id])) { + if ($ports_db[$port_id]['deleted'] != '1') { + dbUpdate(array('deleted' => '1'), 'ports', '`port_id` = ?', array($ports_db[$port_id])); + $ports_db[$port_id]['deleted'] = '1'; echo '-'; } } @@ -68,4 +104,3 @@ echo "\n"; // Clear Variables Here unset($port_stats); unset($ports_db); -unset($ports_db_db); diff --git a/includes/functions.php b/includes/functions.php index f97dd4177..e399a10ae 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -239,12 +239,20 @@ function delete_device($id) { return $ret; } -function addHost($host, $snmpver, $port = '161', $transport = 'udp', $quiet = '0', $poller_group = '0', $force_add = '0') { +function addHost($host, $snmpver, $port = '161', $transport = 'udp', $quiet = '0', $poller_group = '0', $force_add = '0', $port_assoc_mode = 'ifIndex') { global $config; list($hostshort) = explode(".", $host); // Test Database Exists if (host_exists($host) === false) { + // Valid port assoc mode + if (! is_valid_port_assoc_mode ($port_assoc_mode)) { + if ($quiet == 0) { + print_error ("Invalid port association_mode '$port_assoc_mode'. Valid modes are: " . join (', ', get_port_assoc_modes ())); + return 0; + } + } + if ($config['addhost_alwayscheckip'] === TRUE) { $ip = gethostbyname($host); } else { @@ -257,15 +265,15 @@ function addHost($host, $snmpver, $port = '161', $transport = 'udp', $quiet = '0 if (empty($snmpver)) { // Try SNMPv2c $snmpver = 'v2c'; - $ret = addHost($host, $snmpver, $port, $transport, $quiet, $poller_group, $force_add); + $ret = addHost($host, $snmpver, $port, $transport, $quiet, $poller_group, $force_add, $port_assoc_mode); if (!$ret) { //Try SNMPv3 $snmpver = 'v3'; - $ret = addHost($host, $snmpver, $port, $transport, $quiet, $poller_group, $force_add); + $ret = addHost($host, $snmpver, $port, $transport, $quiet, $poller_group, $force_add, $port_assoc_mode); if (!$ret) { // Try SNMPv1 $snmpver = 'v1'; - return addHost($host, $snmpver, $port, $transport, $quiet, $poller_group, $force_add); + return addHost($host, $snmpver, $port, $transport, $quiet, $poller_group, $force_add, $port_assoc_mode); } else { return $ret; @@ -279,12 +287,12 @@ function addHost($host, $snmpver, $port = '161', $transport = 'udp', $quiet = '0 if ($snmpver === "v3") { // Try each set of parameters from config foreach ($config['snmp']['v3'] as $v3) { - $device = deviceArray($host, NULL, $snmpver, $port, $transport, $v3); + $device = deviceArray($host, NULL, $snmpver, $port, $transport, $v3, $port_assoc_mode); if($quiet == '0') { print_message("Trying v3 parameters " . $v3['authname'] . "/" . $v3['authlevel'] . " ... "); } if ($force_add == 1 || isSNMPable($device)) { $snmphost = snmp_get($device, "sysName.0", "-Oqv", "SNMPv2-MIB"); if (empty($snmphost) or ($snmphost == $host || $hostshort = $host)) { - $device_id = createHost ($host, NULL, $snmpver, $port, $transport, $v3, $poller_group); + $device_id = createHost ($host, NULL, $snmpver, $port, $transport, $v3, $poller_group, $port_assoc_mode); return $device_id; } else { @@ -303,14 +311,14 @@ function addHost($host, $snmpver, $port = '161', $transport = 'udp', $quiet = '0 elseif ($snmpver === "v2c" or $snmpver === "v1") { // try each community from config foreach ($config['snmp']['community'] as $community) { - $device = deviceArray($host, $community, $snmpver, $port, $transport, NULL); + $device = deviceArray($host, $community, $snmpver, $port, $transport, NULL, $port_assoc_mode); if($quiet == '0') { print_message("Trying community $community ..."); } if ($force_add == 1 || isSNMPable($device)) { $snmphost = snmp_get($device, "sysName.0", "-Oqv", "SNMPv2-MIB"); if (empty($snmphost) || ($snmphost && ($snmphost == $host || $hostshort = $host))) { - $device_id = createHost ($host, $community, $snmpver, $port, $transport,array(),$poller_group); + $device_id = createHost ($host, $community, $snmpver, $port, $transport,array(),$poller_group, $port_assoc_mode); return $device_id; } else { @@ -382,12 +390,18 @@ next; } } -function deviceArray($host, $community, $snmpver, $port = 161, $transport = 'udp', $v3) { +function deviceArray($host, $community, $snmpver, $port = 161, $transport = 'udp', $v3, $port_assoc_mode = 'ifIndex') { $device = array(); $device['hostname'] = $host; $device['port'] = $port; $device['transport'] = $transport; + /* Get port_assoc_mode id if neccessary + * We can work with names of IDs here */ + if (! is_int ($port_assoc_mode)) + $port_assoc_mode = get_port_assoc_mode_id ($port_assoc_mode); + $device['port_association_mode'] = $port_assoc_mode; + $device['snmpver'] = $snmpver; if ($snmpver === "v2c" or $snmpver === "v1") { $device['community'] = $community; @@ -554,7 +568,7 @@ function getpollergroup($poller_group='0') { } } -function createHost($host, $community = NULL, $snmpver, $port = 161, $transport = 'udp', $v3 = array(), $poller_group='0') { +function createHost($host, $community = NULL, $snmpver, $port = 161, $transport = 'udp', $v3 = array(), $poller_group='0', $port_assoc_mode = 'ifIndex') { global $config; $host = trim(strtolower($host)); @@ -569,6 +583,7 @@ function createHost($host, $community = NULL, $snmpver, $port = 161, $transport 'snmpver' => $snmpver, 'poller_group' => $poller_group, 'status_reason' => '', + 'port_association_mode' => $port_assoc_mode, ); $device = array_merge($device, $v3); diff --git a/includes/polling/port-adsl.inc.php b/includes/polling/port-adsl.inc.php index 883cfcced..e3567e26b 100644 --- a/includes/polling/port-adsl.inc.php +++ b/includes/polling/port-adsl.inc.php @@ -39,11 +39,11 @@ // adslAturPerfESs.1 = 0 seconds // adslAturPerfValidIntervals.1 = 0 // adslAturPerfInvalidIntervals.1 = 0 -if (isset($port_stats[$port['ifIndex']]['adslLineCoding'])) { +if (isset($port_stats[$port_id]['adslLineCoding'])) { // Check to make sure Port data is cached. - $this_port = &$port_stats[$port['ifIndex']]; + $this_port = &$port_stats[$port_id]; - $rrdfile = $config['rrd_dir'].'/'.$device['hostname'].'/'.safename('port-'.$port['ifIndex'].'-adsl.rrd'); + $rrdfile = get_port_rrdfile_path ($device['hostname'], $port_id, 'adsl'); $rrd_create = ' --step 300'; $rrd_create .= ' DS:AtucCurrSnrMgn:GAUGE:600:0:635'; @@ -130,8 +130,8 @@ if (isset($port_stats[$port['ifIndex']]['adslLineCoding'])) { $this_port[$oid] = ($this_port[$oid] / 10); } - if (dbFetchCell('SELECT COUNT(*) FROM `ports_adsl` WHERE `port_id` = ?', array($port['port_id'])) == '0') { - dbInsert(array('port_id' => $port['port_id']), 'ports_adsl'); + if (dbFetchCell('SELECT COUNT(*) FROM `ports_adsl` WHERE `port_id` = ?', array($port_id)) == '0') { + dbInsert(array('port_id' => $port_id), 'ports_adsl'); } $port['adsl_update'] = array('port_adsl_updated' => array('NOW()')); @@ -141,7 +141,7 @@ if (isset($port_stats[$port['ifIndex']]['adslLineCoding'])) { $port['adsl_update'][$oid] = $data; } - dbUpdate($port['adsl_update'], 'ports_adsl', '`port_id` = ?', array($port['port_id'])); + dbUpdate($port['adsl_update'], 'ports_adsl', '`port_id` = ?', array($port_id)); if ($this_port['adslAtucCurrSnrMgn'] > '1280') { $this_port['adslAtucCurrSnrMgn'] = 'U'; diff --git a/includes/polling/port-etherlike.inc.php b/includes/polling/port-etherlike.inc.php index 0576d4b19..bf947b92d 100644 --- a/includes/polling/port-etherlike.inc.php +++ b/includes/polling/port-etherlike.inc.php @@ -1,13 +1,14 @@ -// -- i can make it a function, so that you don't know what it's doing. -// -- $ports = adamasMagicFunction($ports_db); ? -// select * doesn't do what we want if multiple tables have the same column name -- last one wins :/ -$ports_db = dbFetchRows('SELECT *, `ports_statistics`.`port_id` AS `ports_statistics_port_id`, `ports`.`port_id` AS `port_id` FROM `ports` LEFT OUTER JOIN `ports_statistics` ON `ports`.`port_id` = `ports_statistics`.`port_id` WHERE `ports`.`device_id` = ?', array($device['device_id'])); +// By default libreNMS uses the ifIndex to associate ports on devices with ports discoverd/polled +// before and stored in the database. On Linux boxes this is a problem as ifIndexes may be +// unstable between reboots or (re)configuration of tunnel interfaces (think: GRE/OpenVPN/Tinc/...) +// The port association configuration allows to choose between association via ifIndex, ifName, +// or maybe other means in the future. The default port association mode still is ifIndex for +// compatibility reasons. +$port_association_mode = $config['default_port_association_mode']; +if ($device['port_association_mode']) + $port_association_mode = get_port_assoc_mode_name ($device['port_association_mode']); -foreach ($ports_db as $port) { - $ports[$port['ifIndex']] = $port; +// Query known ports and mapping table in order of discovery to make sure +// the latest discoverd/polled port is in the mapping tables. +$ports_mapped = get_ports_mapped ($device['device_id'], true); +$ports = $ports_mapped['ports']; + +// +// Rename any old RRD files still named after the previous ifIndex based naming schema. +foreach ($ports_mapped['maps']['ifIndex'] as $ifIndex => $port_id) { + foreach (array ('', 'adsl', 'dot3') as $suffix) { + $suffix_tmp = ''; + if ($suffix) + $suffix_tmp = "-$suffix"; + + $old_rrd_path = trim ($config['rrd_dir']) . '/' . $device['hostname'] . "/port-$ifIndex$suffix_tmp.rrd"; + $new_rrd_path = get_port_rrdfile_path ($device['hostname'], $port_id, $suffix); + + if (is_file ($old_rrd_path)) { + rename ($old_rrd_path, $new_rrd_path); + } + } } + // New interface detection foreach ($port_stats as $ifIndex => $port) { + // Store ifIndex in port entry and prefetch ifName as we'll need it multiple times + $port['ifIndex'] = $ifIndex; + $ifName = $port['ifName']; + + // Get port_id according to port_association_mode used for this device + $port_id = get_port_id ($ports_mapped, $port, $port_association_mode); + if (is_port_valid($port, $device)) { echo 'valid'; - if (!is_array($ports[$port['ifIndex']])) { - $port_id = dbInsert(array('device_id' => $device['device_id'], 'ifIndex' => $ifIndex), 'ports'); + + // Port newly discovered? + if (! $ports[$port_id]) { + $port_id = dbInsert(array('device_id' => $device['device_id'], 'ifIndex' => $ifIndex, 'ifName' => $ifName), 'ports'); dbInsert(array('port_id' => $port_id), 'ports_statistics'); - $ports[$port['ifIndex']] = dbFetchRow('SELECT * FROM `ports` WHERE `port_id` = ?', array($port_id)); - echo 'Adding: '.$port['ifName'].'('.$ifIndex.')('.$ports[$port['ifIndex']]['port_id'].')'; + $ports[$port_id] = dbFetchRow('SELECT * FROM `ports` WHERE `port_id` = ?', array($port_id)); + echo 'Adding: '.$ifName.'('.$ifIndex.')('.$port_id.')'; // print_r($ports); } - else if ($ports[$ifIndex]['deleted'] == '1') { - dbUpdate(array('deleted' => '0'), 'ports', '`port_id` = ?', array($ports[$ifIndex]['port_id'])); - $ports[$ifIndex]['deleted'] = '0'; - } - if ($ports[$ifIndex]['ports_statistics_port_id'] === null) { - // in case the port was created before we created the table - dbInsert(array('port_id' => $ports[$ifIndex]['port_id']), 'ports_statistics'); - } - } - else { - if ($ports[$port['ifIndex']]['deleted'] != '1') { - dbUpdate(array('deleted' => '1'), 'ports', '`port_id` = ?', array($ports[$ifIndex]['port_id'])); - $ports[$ifIndex]['deleted'] = '1'; - } - } -} -// End New interface detection + // Port re-discovered after previous deletion? + else if ($ports[$port_id]['deleted'] == 1) { + dbUpdate(array('deleted' => '0'), 'ports', '`port_id` = ?', array($port_id)); + $ports[$port_id]['deleted'] = '0'; + } + if ($ports[$port_id]['ports_statistics_port_id'] === null) { + // in case the port was created before we created the table + dbInsert(array('port_id' => $port_id), 'ports_statistics'); + } + + // Assure stable mapping + $port_stats[$ifIndex]['port_id'] = $port_id; + $ports[$port_id]['ifIndex'] = $ifIndex; + } + + // Port vanished (mark as deleted) + else { + if ($ports[$port_id]['deleted'] != '1') { + dbUpdate(array('deleted' => '1'), 'ports', '`port_id` = ?', array($port_id)); + $ports[$port_id]['deleted'] = '1'; + } + } +} // End new interface detection + + echo "\n"; // Loop ports in the DB and update where necessary foreach ($ports as $port) { - echo 'Port '.$port['ifDescr'].'('.$port['ifIndex'].') '; + $port_id = $port['port_id']; + + echo 'Port ' . $port['ifName'] . ': ' . $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']]; @@ -477,7 +518,7 @@ foreach ($ports as $port) { } // Update RRDs - $rrdfile = $host_rrd.'/port-'.safename($port['ifIndex'].'.rrd'); + $rrdfile = get_port_rrdfile_path ($device['hostname'], $port_id); if (!is_file($rrdfile)) { rrdtool_create( $rrdfile, @@ -576,9 +617,9 @@ foreach ($ports as $port) { // Update Database if (count($port['update'])) { - $updated = dbUpdate($port['update'], 'ports', '`port_id` = ?', array($port['port_id'])); + $updated = dbUpdate($port['update'], 'ports', '`port_id` = ?', array($port_id)); // do we want to do something else with this? - $updated += dbUpdate($port['update_extended'], 'ports_statistics', '`port_id` = ?', array($port['port_id'])); + $updated += dbUpdate($port['update_extended'], 'ports_statistics', '`port_id` = ?', array($port_id)); d_echo("$updated updated"); } @@ -588,7 +629,7 @@ foreach ($ports as $port) { 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'])); + dbUpdate(array('deleted' => '1'), 'ports', '`device_id` = ? AND `port_id` = ?', array($device['device_id'], $port_id)); } } else { @@ -599,7 +640,7 @@ foreach ($ports as $port) { // Clear Per-Port Variables Here unset($this_port); -}//end foreach +} //end port update // Clear Variables Here unset($port_stats); diff --git a/scripts/tune_port.php b/scripts/tune_port.php index 2798469cc..14b62abe6 100755 --- a/scripts/tune_port.php +++ b/scripts/tune_port.php @@ -24,8 +24,7 @@ foreach (dbFetchRows("SELECT `device_id`,`hostname` FROM `devices` WHERE `hostna echo "Found hostname " . $device['hostname'].".......\n"; foreach (dbFetchRows("SELECT `ifIndex`,`ifName`,`ifSpeed` FROM `ports` WHERE `ifName` LIKE ? AND `device_id` = ?", array('%'.$ports.'%',$device['device_id'])) as $port) { echo "Tuning port " . $port['ifName'].".......\n"; - $host_rrd = $config['rrd_dir'].'/'.$device['hostname']; - $rrdfile = $host_rrd.'/port-'.safename($port['ifIndex'].'.rrd'); + $rrdfile = get_port_rrdfile_path ($device['hostname'], $port['port_id']); rrdtool_tune('port',$rrdfile,$port['ifSpeed']); } } diff --git a/sql-schema/096.sql b/sql-schema/096.sql new file mode 100644 index 000000000..58ae65201 --- /dev/null +++ b/sql-schema/096.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS `port_association_mode` (pom_id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, name varchar(12) NOT NULL); +INSERT INTO port_association_mode (pom_id, name) values (1, 'ifIndex'); +INSERT INTO port_association_mode (name) values ('ifName'); +INSERT INTO port_association_mode (name) values ('ifDescr'); +ALTER TABLE devices ADD port_association_mode int(11) NOT NULL DEFAULT 1;