296 lines
12 KiB
PHP
296 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* Observium
|
|
*
|
|
* This file is part of Observium.
|
|
*
|
|
* @package observium
|
|
* @subpackage discovery
|
|
* @copyright (C) Adam Armstrong
|
|
*
|
|
*/
|
|
|
|
// 'BGP4-MIB', 'CISCO-BGP4-MIB', 'BGP4-V2-MIB-JUNIPER', 'FORCE10-BGP4-V2-MIB', 'ARISTA-BGP4V2-MIB', 'FOUNDRY-BGP4V2-MIB', 'HUAWEI-BGP-VPN-MIB'
|
|
if (!$config['enable_bgp'] || !is_device_mib($device, 'BGP4-MIB')) {
|
|
// Note, BGP4-MIB is main MIB, without it, the rest will not be checked
|
|
if ($device['bgpLocalAs']) {
|
|
// FIXME. Clean old discovered peers?
|
|
log_event('BGP Local ASN removed: AS' . $device['bgpLocalAs'], $device, 'device', $device['device_id']);
|
|
dbUpdate([ 'bgpLocalAs' => [ 'NULL' ] ], 'devices', 'device_id = ?', [ $device['device_id'] ]);
|
|
print_cli_data("Updated ASN", $device['bgpLocalAs'] . " -> ''", 2);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Get Local ASN
|
|
|
|
// Get an array with existed MIBs on a device with LocasAs-es
|
|
$local_as_array = get_bgp_localas_array($device);
|
|
|
|
$vendor_mib = FALSE; // CLEANME. Clear after full rewrite to definitions.
|
|
$bgpVrfLocalAs = [];
|
|
foreach ($local_as_array as $entry) {
|
|
|
|
// CLEANME. Clear after full rewrite to definitions.
|
|
if ($entry['mib'] !== 'BGP4-MIB' && $entry['mib'] !== 'CISCO-BGP4-MIB') {
|
|
$vendor_mib = $entry['mib'];
|
|
}
|
|
|
|
// LocalAs by first non-zero
|
|
if ($entry['LocalAs'] != 0) {
|
|
if (!isset($bgpLocalAs) &&
|
|
$entry['oid'] !== 'cbgpPeer2LocalAs') {
|
|
// Do not use Cisco Peer LocalAs as device bgp, see https://jira.observium.org/browse/OBS-4116
|
|
$bgpLocalAs = $entry['LocalAs'];
|
|
}
|
|
if (isset($entry['virtual_name']) && !isset($bgpVrfLocalAs[$entry['virtual_name']])) {
|
|
// Set per vrf LocalAs
|
|
$bgpVrfLocalAs[$entry['virtual_name']] = $entry['LocalAs'];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Discover BGP peers
|
|
|
|
/// NOTE. PeerIdentifier != PeerRemoteAddr
|
|
|
|
if (is_numeric($bgpLocalAs) && $bgpLocalAs != 0) {
|
|
print_cli_data("Local AS", "AS$bgpLocalAs ", 2);
|
|
|
|
// Detect if Local AS changed
|
|
if ($bgpLocalAs != $device['bgpLocalAs']) {
|
|
if (!$device['bgpLocalAs']) {
|
|
log_event('BGP Local ASN added: AS' . $bgpLocalAs, $device, 'device', $device['device_id']);
|
|
} elseif (!$bgpLocalAs) {
|
|
log_event('BGP Local ASN removed: AS' . $device['bgpLocalAs'], $device, 'device', $device['device_id']);
|
|
} else {
|
|
log_event('BGP ASN changed: AS' . $device['bgpLocalAs'] . ' -> AS' . $bgpLocalAs, $device, 'device', $device['device_id']);
|
|
}
|
|
dbUpdate(['bgpLocalAs' => $bgpLocalAs], 'devices', 'device_id = ?', [$device['device_id']]);
|
|
print_cli_data("Updated ASN", $device['bgpLocalAs'] . " -> $bgpLocalAs", 2);
|
|
}
|
|
|
|
print_cli_data_field("Caching");
|
|
|
|
// Init
|
|
$p_list = []; // valid_peers
|
|
$peerlist = [];
|
|
$af_list = [];
|
|
|
|
foreach ($local_as_array as $entry) {
|
|
$mib = $entry['mib'];
|
|
echo("$mib ");
|
|
if ($check_vrfs = isset($entry['virtual_name'])) {
|
|
// Keep original
|
|
$device_original = $device;
|
|
$bgpLocalAs_original = $bgpLocalAs;
|
|
if (isset($bgpVrfLocalAs[$entry['virtual_name']])) {
|
|
// Need in per VRF discovery
|
|
$bgpLocalAs = $bgpVrfLocalAs[$entry['virtual_name']];
|
|
}
|
|
$vrf_name = $entry['virtual_name'];
|
|
$snmp_virtual = $entry['snmp_context'];
|
|
// Set device for VRF tables
|
|
$device = snmp_virtual_device($device_original, $snmp_virtual);
|
|
echo("(Virtual Routing $vrf_name) ");
|
|
} elseif ($entry['vrf_name']) {
|
|
// only stored VRF name, ie CUMULUS-BGPVRF-MIB
|
|
$vrf_name = $entry['vrf_name'];
|
|
echo("(Virtual Routing $vrf_name) ");
|
|
}
|
|
|
|
/* Start caching bgp peers */
|
|
$include = __DIR__ . '/bgp/' . strtolower($mib) . '.inc.php';
|
|
if (!is_file($include)) {
|
|
// Common for vendor mibs
|
|
$include = __DIR__ . '/bgp/bgp4v2-mib.inc.php';
|
|
}
|
|
include $include;
|
|
/* End caching bgp peers */
|
|
|
|
if ($check_vrfs) {
|
|
// Restore device array
|
|
$device = $device_original;
|
|
$bgpLocalAs = $bgpLocalAs_original;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
echo("No BGP on host");
|
|
if (is_numeric($device['bgpLocalAs'])) {
|
|
log_event('BGP ASN removed: AS' . $device['bgpLocalAs'], $device, 'device', $device['device_id']);
|
|
dbUpdate([ 'bgpLocalAs' => [ 'NULL' ] ], 'devices', 'device_id = ?', [$device['device_id']]);
|
|
print_message('Removed ASN (' . $device['bgpLocalAs'] . ')');
|
|
} # End if
|
|
} # End if
|
|
|
|
// Process discovered peers
|
|
|
|
global $table_rows;
|
|
$table_rows = [];
|
|
|
|
if (!safe_empty($peerlist)) {
|
|
print_debug_vars($peerlist);
|
|
|
|
echo(PHP_EOL);
|
|
// Filter IP search by BGP enabled devices (without self)
|
|
$bgp_device_ids = dbFetchColumn('SELECT `device_id` FROM `devices` WHERE `device_id` != ? AND `bgpLocalAs` > 0 AND `disabled` = 0 AND `status` = 1', [$device['device_id']]);
|
|
$peer_as_where = generate_query_values_and($bgp_device_ids, 'device_id');
|
|
|
|
$peer_devices = [];
|
|
$peer_devices_ids = [];
|
|
foreach (dbFetchRows('SELECT `device_id`, `bgpPeerLocalAddr`, `bgpPeerRemoteAddr` FROM `bgpPeers` WHERE `bgpPeerRemoteAs` = ?' . $peer_as_where, [$bgpLocalAs]) as $entry) {
|
|
$peer_devices[$entry['bgpPeerLocalAddr']][$entry['bgpPeerRemoteAddr']] = $entry['device_id'];
|
|
$peer_devices_ids[] = $entry['device_id'];
|
|
}
|
|
print_debug_vars($peer_devices);
|
|
|
|
$peer_ip_where = generate_query_values_and($peer_devices_ids, 'device_id') . generate_query_values_and('up', 'ifOperStatus');
|
|
|
|
foreach ($peerlist as $peer) {
|
|
|
|
$astext = get_astext($peer['as']);
|
|
$reverse_dns = gethostbyaddr6($peer['ip']);
|
|
if ($reverse_dns == $peer['ip']) {
|
|
$reverse_dns = '';
|
|
}
|
|
|
|
// Search a remote device if possible
|
|
$peer_addr_version = get_ip_version($peer['ip']);
|
|
|
|
$peer_device_id = get_peer_remote_device_id($peer, $peer_devices, $peer_ip_where);
|
|
$peer_device = is_numeric($peer_device_id) ? device_by_id_cache($peer_device_id) : [];
|
|
|
|
//$peer['local_as'] = (isset($peer['local_as']) && $peer['local_as'] != 0 && $peer['local_as'] != '') ? $peer['local_as'] : $bgpLocalAs;
|
|
$local_as = $peer['local_as'];
|
|
if (isset($peer['virtual_name'])) {
|
|
$local_as .= ' (' . $peer['virtual_name'] . ')';
|
|
}
|
|
$table_rows[$peer['ip']] = [ $local_as, $peer['local_ip'], $peer['as'], $peer['ip'], '', $reverse_dns, truncate($peer_device['hostname'], 30) ];
|
|
$params = [
|
|
'device_id' => $device['device_id'],
|
|
'bgpPeerIdentifier' => $peer['identifier'],
|
|
'bgpPeerRemoteAddr' => $peer['ip'],
|
|
'bgpPeerLocalAddr' => $peer['local_ip'],
|
|
'local_as' => $peer['local_as'],
|
|
'bgpPeerRemoteAs' => $peer['as'],
|
|
'astext' => $astext,
|
|
'reverse_dns' => $reverse_dns,
|
|
'virtual_name' => $peer['virtual_name'] ?? [ 'NULL' ],
|
|
'peer_device_id' => $peer_device_id ?: [ 'NULL' ]
|
|
];
|
|
|
|
$peer_db = dbFetchRow('SELECT * FROM `bgpPeers` WHERE `device_id` = ? AND `bgpPeerRemoteAddr` = ?', [$device['device_id'], $peer['ip']]);
|
|
if (!safe_empty($peer_db)) {
|
|
$update_array = [];
|
|
foreach ($params as $param => $value) {
|
|
|
|
if ($value === ['NULL']) {
|
|
if ($peer_db[$param] != '') {
|
|
$update_array[$param] = $value;
|
|
}
|
|
} elseif ($value != $peer_db[$param]) {
|
|
$update_array[$param] = $value;
|
|
}
|
|
}
|
|
|
|
if ($update_count = count($update_array)) {
|
|
dbUpdate($update_array, 'bgpPeers', '`device_id` = ? AND `bgpPeerRemoteAddr` = ?', [$device['device_id'], $peer['ip']]);
|
|
if (isset($update_array['reverse_dns']) && $update_count === 1) {
|
|
// Do not count updates if changed only reverse DNS
|
|
$GLOBALS['module_stats'][$module]['unchanged']++;
|
|
} else {
|
|
$GLOBALS['module_stats'][$module]['updated']++;
|
|
}
|
|
} else {
|
|
$GLOBALS['module_stats'][$module]['unchanged']++;
|
|
}
|
|
|
|
$peer_id = $peer_db['bgpPeer_id'];
|
|
} else {
|
|
$peer_id = dbInsert($params, 'bgpPeers');
|
|
$GLOBALS['module_stats'][$module]['added']++;
|
|
}
|
|
|
|
$peer['id'] = $peer_id;
|
|
$peer_ids[$peer['ip']] = $peer_id;
|
|
|
|
// AFI/SAFI for specific vendors
|
|
if (isset($peer_afis[$peer['ip']])) {
|
|
$peer_index = $peer['index']; // keep original
|
|
foreach ($peer_afis[$peer['ip']] as $af_entry) {
|
|
$peer['index'] = $af_entry['index'] ?? $peer_index;
|
|
discovery_bgp_afisafi($device, $peer, $af_entry['afi'], $af_entry['safi'], $af_list);
|
|
}
|
|
$peer['index'] = $peer_index; // restore
|
|
}
|
|
|
|
// Autodiscovery for bgp neighbours
|
|
if ($config['autodiscovery']['bgp']) {
|
|
if (($peer['as'] == $device['bgpLocalAs']) || // ASN matches local router
|
|
($config['autodiscovery']['bgp_as_private'] && is_bgp_as_private($peer['as'])) || // ASN is private
|
|
(is_array($config['autodiscovery']['bgp_as_whitelist']) && in_array($peer['as'], $config['autodiscovery']['bgp_as_whitelist']))) { // ASN is in bgp_as_whitelist
|
|
|
|
// Try find remote device and check if already cached
|
|
$remote_device_id = get_autodiscovery_device_id($device, $peer['ip']);
|
|
if (is_null($remote_device_id) && // NULL - never cached in other rounds
|
|
check_autodiscovery($peer['ip'])) { // Check all previous autodiscovery rounds
|
|
// Neighbour never checked, try autodiscover
|
|
$remote_device_id = autodiscovery_device($peer['ip'], NULL, 'BGP', NULL, $device);
|
|
}
|
|
}
|
|
}
|
|
} # Foreach
|
|
|
|
// Remove deleted AFI/SAFI
|
|
unset($afi, $safi, $peer_ip, $peer_id);
|
|
$cbgp_delete = [];
|
|
$query = 'SELECT * FROM `bgpPeers_cbgp` WHERE `device_id` = ?';
|
|
foreach (dbFetchRows($query, [$device['device_id']]) as $entry) {
|
|
$peer_id = $entry['bgpPeer_id'];
|
|
$afi = $entry['afi'];
|
|
$safi = $entry['safi'];
|
|
$cbgp_id = $entry['cbgp_id'];
|
|
|
|
if (!isset($af_list[$peer_id][$afi][$safi])) {
|
|
$cbgp_delete[] = $cbgp_id;
|
|
//dbDelete('bgpPeers_cbgp', '`cbgp_id` = ?', array($cbgp_id));
|
|
}
|
|
} # AF list
|
|
if (safe_count($cbgp_delete)) {
|
|
// Multi-delete
|
|
dbDelete('bgpPeers_cbgp', generate_query_values($cbgp_delete, 'cbgp_id'));
|
|
}
|
|
unset($af_list, $cbgp_delete);
|
|
} # end peerlist
|
|
|
|
// Delete removed peers
|
|
unset($peer_ip, $peer_as);
|
|
$peers_delete = [];
|
|
$query = 'SELECT * FROM `bgpPeers` WHERE `device_id` = ?';
|
|
foreach (dbFetchRows($query, [$device['device_id']]) as $entry) {
|
|
$peer_ip = $entry['bgpPeerRemoteAddr'];
|
|
$peer_as = $entry['bgpPeerRemoteAs'];
|
|
|
|
if (!isset($p_list[$peer_ip][$peer_as])) {
|
|
// dbDelete('bgpPeers', '`bgpPeer_id` = ?', [ $entry['bgpPeer_id'] ]);
|
|
$peers_delete[] = $entry['bgpPeer_id'];
|
|
$GLOBALS['module_stats'][$module]['deleted']++;
|
|
} else {
|
|
// Unset, for exclude duplicate entries in DB
|
|
unset($p_list[$peer_ip][$peer_as]);
|
|
}
|
|
}
|
|
if (count($peers_delete)) {
|
|
// Multi-delete
|
|
dbDelete('bgpPeers', generate_query_values($peers_delete, 'bgpPeer_id'));
|
|
dbDelete('bgpPeers_cbgp', generate_query_values($peers_delete, 'bgpPeer_id'));
|
|
}
|
|
|
|
$table_headers = ['%WLocal: AS (VRF)%n', '%WIP%n', '%WPeer: AS%n', '%WIP%n', '%WFamily%n', '%WrDNS%n', '%WRemote Device%n'];
|
|
print_cli_table($table_rows, $table_headers);
|
|
|
|
unset($p_list, $peerlist, $vendor_mib, $cisco_version, $cisco_peers, $table_rows, $table_headers, $peer_devices, $peer_devices_ids);
|
|
|
|
// EOF
|