refactor: rewrite arp-table discovery (#5048)

This commit is contained in:
Tony Murray
2016-11-25 21:14:35 +00:00
committed by Neil Lathwood
parent 48b0e53a54
commit da3d687c6d
2 changed files with 77 additions and 74 deletions
-5
View File
@@ -232,11 +232,6 @@ function get_all_devices($device, $type = "")
return $devices;
}
function port_by_id_cache($port_id)
{
return get_port_by_id_cache('port', $port_id);
}
function table_from_entity_type($type)
{
// Fuck you, english pluralisation.
+77 -69
View File
@@ -1,6 +1,27 @@
<?php
unset($mac_table);
/**
* arp-table.php
*
* Collect arp table entries from devices and update the database
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2016 Tony Murray
* @author Tony Murray <[email protected]>
*/
if (key_exists('vrf_lite_cisco', $device) && (count($device['vrf_lite_cisco'])!=0)) {
$vrfs_lite_cisco = $device['vrf_lite_cisco'];
@@ -9,86 +30,73 @@ if (key_exists('vrf_lite_cisco', $device) && (count($device['vrf_lite_cisco'])!=
}
foreach ($vrfs_lite_cisco as $vrf) {
$device['context_name']=$vrf['context_name'];
$context = $vrf['context_name'];
$device['context_name']=$context;
$arp_oid = 'ipNetToPhysicalPhysAddress';
$ipNetToPhysical_data = snmp_walk($device, $arp_oid, '-Oq', 'IP-MIB');
if (empty($ipNetToPhysical_data)) {
$arp_oid = 'ipNetToMediaPhysAddress';
$ipNetToPhysical_data = snmp_walk($device, $arp_oid, '-Oq', 'IP-MIB');
}
$ipNetToPhysical_data = str_replace('IP-MIB::'.$arp_oid.'.', '', trim($ipNetToPhysical_data));
$ipNetToPhysical_data = str_replace('"', '', trim($ipNetToPhysical_data));
foreach (explode("\n", $ipNetToPhysical_data) as $data) {
list($oid, $mac) = explode(' ', $data);
list($if, $ipv, $first, $second, $third, $fourth) = explode('.', $oid);
$ip = $first.'.'.$second.'.'.$third.'.'.$fourth;
if ($ip != '...' && $ipv === 'ipv4' && $mac != '0:0:0:0:0:0') {
$interface = dbFetchRow('SELECT * FROM `ports` WHERE `device_id` = ? AND `ifIndex` = ?', array($device['device_id'], $if));
$arp_data = snmpwalk_cache_multi_oid($device, 'ipNetToPhysicalPhysAddress', array(), 'IP-MIB');
$arp_data = snmpwalk_cache_multi_oid($device, 'ipNetToMediaPhysAddress', $arp_data, 'IP-MIB');
list($m_a, $m_b, $m_c, $m_d, $m_e, $m_f) = explode(':', $mac);
$m_a = zeropad($m_a);
$m_b = zeropad($m_b);
$m_c = zeropad($m_c);
$m_d = zeropad($m_d);
$m_e = zeropad($m_e);
$m_f = zeropad($m_f);
$md_a = hexdec($m_a);
$md_b = hexdec($m_b);
$md_c = hexdec($m_c);
$md_d = hexdec($m_d);
$md_e = hexdec($m_e);
$md_f = hexdec($m_f);
$mac = "$m_a:$m_b:$m_c:$m_d:$m_e:$m_f";
$sql = "SELECT M.* from ipv4_mac AS M, ports AS I WHERE M.port_id=I.port_id AND I.device_id=? AND M.context_name=?";
$params = array($device['device_id'], $context);
$existing_data = dbFetchRows($sql, $params);
$mac_table[$if][$mac]['ip'] = $ip;
$mac_table[$if][$mac]['ciscomac'] = "$m_a$m_b.$m_c$m_d.$m_e$m_f";
$clean_mac = $m_a.$m_b.$m_c.$m_d.$m_e.$m_f;
$mac_table[$if][$mac]['cleanmac'] = $clean_mac;
$port_id = $interface['port_id'];
$mac_table[$port_id][$clean_mac][$ip] = 1;
$arp_table = array();
$insert_data = array();
foreach ($arp_data as $ip => $data) {
if (isset($data['ipNetToPhysicalPhysAddress'])) {
$raw_mac = $data['ipNetToPhysicalPhysAddress'];
list($if, $ipv, $ip) = explode('.', $ip, 3);
} elseif (isset($data['ipNetToMediaPhysAddress'])) {
$raw_mac = $data['ipNetToMediaPhysAddress'];
list($if, $ip) = explode('.', $ip, 2);
$ipv = 'ipv4';
}
if (dbFetchCell('SELECT COUNT(*) from ipv4_mac WHERE port_id = ? AND ipv4_address = ?', array($interface['port_id'], $ip))) {
// Commented below, no longer needed but leaving for reference.
// $sql = "UPDATE `ipv4_mac` SET `mac_address` = '$clean_mac' WHERE port_id = '".$interface['port_id']."' AND ipv4_address = '$ip'";
$old_mac = dbFetchCell('SELECT mac_address from ipv4_mac WHERE ipv4_address=? AND port_id=?', array($ip, $interface['port_id']));
$interface = get_port_by_index_cache($device['device_id'], $if);
$port_id = $interface['port_id'];
if ($clean_mac != $old_mac && $clean_mac != '' && $old_mac != '') {
d_echo("Changed mac address for $ip from $old_mac to $clean_mac\n");
if (!empty($ip) && $ipv === 'ipv4' && $raw_mac != '0:0:0:0:0:0' && !isset($arp_table[$port_id][$ip])) {
$mac = implode(array_map('zeropad', explode(':', $raw_mac)));
$arp_table[$port_id][$ip] = $mac;
log_event("MAC change: $ip : ".mac_clean_to_readable($old_mac).' -> '.mac_clean_to_readable($clean_mac), $device, 'interface', $interface['port_id']);
$index = array_search($ip, array_column($existing_data, 'ipv4_address'));
if ($index !== false) {
$old_mac = $existing_data[$index]['mac_address'];
if ($mac != $old_mac && $mac != '') {
d_echo("Changed mac address for $ip from $old_mac to $mac\n");
log_event("MAC change: $ip : ".mac_clean_to_readable($old_mac).' -> '.mac_clean_to_readable($mac), $device, 'interface', $port_id);
dbUpdate(array('mac_address' => $mac), 'ipv4_mac', 'port_id=? AND ipv4_address=? AND context_name=?', array($port_id, $ip, $context));
}
dbUpdate(array('mac_address' => $clean_mac, 'context_name' => $device['context_name']), 'ipv4_mac', 'port_id=? AND ipv4_address=?', array($interface['port_id'], $ip));
echo '.';
d_echo(null, '.');
} elseif (isset($interface['port_id'])) {
echo '+';
// echo("Add MAC $mac\n");
$insert_data = array(
'port_id' => $interface['port_id'],
'mac_address' => $clean_mac,
'ipv4_address' => $ip,
'context_name' => $device['context_name'],
);
dbInsert($insert_data, 'ipv4_mac');
}//end if
}//end if
}//end foreach
d_echo(null, '+');
$insert_data[] = array(
'port_id' => $port_id,
'mac_address' => $mac,
'ipv4_address' => $ip,
'context_name' => $context,
);
}
}
}
$sql = "SELECT * from ipv4_mac AS M, ports as I WHERE M.port_id = I.port_id and I.device_id = '".$device['device_id']."'";
foreach (dbFetchRows($sql) as $entry) {
// add new entries
if (!empty($insert_data)) {
dbBulkInsert($insert_data, 'ipv4_mac');
}
// remove stale entries
foreach ($existing_data as $entry) {
$entry_mac = $entry['mac_address'];
$entry_if = $entry['port_id'];
$entry_ip = $entry['ipv4_address'];
if (!$mac_table[$entry_if][$entry_mac][$entry_ip]) {
dbDelete('ipv4_mac', '`port_id` = ? AND `mac_address` = ? AND `ipv4_address` = ? ', array($entry_if, $entry_mac, $entry_ip));
d_echo("Removing MAC $entry_mac from interface ".$interface['ifName']);
echo '-';
if ($arp_table[$entry_if][$entry_ip] != $entry_mac) {
dbDelete('ipv4_mac', '`port_id` = ? AND `mac_address`=? AND `ipv4_address`=? AND `context_name`=?', array($entry_if, $entry_mac, $entry_ip, $context));
d_echo(null, '-');
}
}
echo "\n";
unset($mac);
echo PHP_EOL;
unset($existing_data, $arp_table, $insert_data, $sql, $params, $context);
unset($device['context_name']);
}
unset($vrfs_c);
unset($vrfs_lite_cisco);