Hello, community.
I was able to write scripts that discovers and poll BGP information from vdom enabled Fortigates. I need help/information how/where to share scripts so it can be useful for other members. Have in mind that I am pretty new to scripting and I suppose that it can be done better and integrated better with LibreNMS Here are some screenshots:
If the code is in our standard polling and discovery methods then create a pull request on GitHub. If this is completely bespoke then post here.
I have created discovery script in /opt/librenms/includes/discovery/bgp-peers/fortigate.inc.php, as in /opt/librenms/includes/discovery/bgp-peers.inc.php there is a os detection code.
for polling i have added to /opt/librenms/includes/polling/bgp-peers.inc.php os detection so I don`t make a mess and redirect execution in different file, which i believe it is not standard polling and discovery methods.
cat includes/discovery/bgp-peers/fortigate.inc.php
<?php
echo "Starting FortiGate BGP Discovery\n";
// Get VDOMs (Virtual Domains)
$vdoms = snmpwalk_cache_oid($device, 'fgVdEntName', [], 'FORTINET-FORTIGATE-MIB');
if (empty($vdoms)) {
echo "No VDOMs detected. Exiting.\n";
return;
}
// Iterate over each VDOM
foreach ($vdoms as $vd_index => $vd) {
$vdom_name = $vd['fgVdEntName'];
echo "Polling BGP for VDOM: $vdom_name (Index: $vd_index)\n";
// Get BGP Local AS
$bgp_local_as = snmp_get($device, "bgpLocalAs.$vd_index", '-Oqv', 'BGP4-MIB');
if (!$bgp_local_as) {
echo "No BGP Local AS found. Skipping VDOM.\n";
continue;
}
echo "VDOM $vdom_name (Index: $vd_index) AS$bgp_local_as\n";
// Get all required BGP SNMP values in one batch to optimize performance
$bgp_data = [
'bgpPeerRemoteAs' => [],
'bgpPeerState' => [],
'bgpPeerAdminStatus' => [],
'bgpPeerLocalAddr' => [],
'bgpPeerInUpdates' => [],
'bgpPeerOutUpdates' => [],
'bgpPeerInTotalMessages' => [],
'bgpPeerOutTotalMessages' => [],
'bgpPeerFsmEstablishedTime' => [],
'bgpPeerInUpdateElapsedTime' => []
];
foreach (array_keys($bgp_data) as $oid) {
$bgp_data[$oid] = snmpwalk_cache_oid($device, $oid, [], 'BGP4-MIB');
}
// Process each BGP peer
foreach ($bgp_data['bgpPeerRemoteAs'] as $peer_oid => $peer) {
$peer_remote_as = $peer['bgpPeerRemoteAs'];
// **Remove trailing VDOM index from peer IP**
$peer_ip_parts = explode('.', $peer_oid);
array_pop($peer_ip_parts); // Remove last segment (VDOM index)
$peer_ip = implode('.', $peer_ip_parts);
// Gather additional values with defaults
$peer_state = $bgp_data['bgpPeerState'][$peer_oid]['bgpPeerState'] ?? 0;
$peer_admin = $bgp_data['bgpPeerAdminStatus'][$peer_oid]['bgpPeerAdminStatus'] ?? 0;
$peer_local_addr = $bgp_data['bgpPeerLocalAddr'][$peer_oid]['bgpPeerLocalAddr'] ?? '0.0.0.0';
$peer_in_updates = $bgp_data['bgpPeerInUpdates'][$peer_oid]['bgpPeerInUpdates'] ?? 0;
$peer_out_updates = $bgp_data['bgpPeerOutUpdates'][$peer_oid]['bgpPeerOutUpdates'] ?? 0;
$peer_in_messages = $bgp_data['bgpPeerInTotalMessages'][$peer_oid]['bgpPeerInTotalMessages'] ?? 0;
$peer_out_messages = $bgp_data['bgpPeerOutTotalMessages'][$peer_oid]['bgpPeerOutTotalMessages'] ?? 0;
$peer_fsm_time = $bgp_data['bgpPeerFsmEstablishedTime'][$peer_oid]['bgpPeerFsmEstablishedTime'] ?? 0;
$peer_update_elapsed = $bgp_data['bgpPeerInUpdateElapsedTime'][$peer_oid]['bgpPeerInUpdateElapsedTime'] ?? 0;
echo "Found peer $peer_ip (AS$peer_remote_as) in VDOM: $vdom_name\n";
// Check if entry already exists using cleaned `peer_ip`
$existing = dbFetchRow("SELECT bgpPeer_id FROM `bgpPeers` WHERE device_id = ? AND bgpPeerIdentifier = ? AND context_name = ?",
[$device['device_id'], $peer_ip, $vdom_name]);
$db_data = [
'bgpPeerState' => $peer_state,
'bgpPeerAdminStatus' => $peer_admin,
'bgpLocalAddr' => $peer_local_addr,
'bgpPeerInUpdates' => $peer_in_updates,
'bgpPeerOutUpdates' => $peer_out_updates,
'bgpPeerInTotalMessages' => $peer_in_messages,
'bgpPeerOutTotalMessages' => $peer_out_messages,
'bgpPeerFsmEstablishedTime' => $peer_fsm_time,
'bgpPeerInUpdateElapsedTime' => $peer_update_elapsed
];
if ($existing) {
// Update existing entry
dbUpdate($db_data, 'bgpPeers', 'device_id = ? AND bgpPeerIdentifier = ? AND context_name = ?',
[$device['device_id'], $peer_ip, $vdom_name]);
} else {
// Insert new entry
$db_data += [
'device_id' => $device['device_id'],
'bgpPeerIdentifier' => $peer_ip,
'bgpPeerRemoteAs' => $peer_remote_as,
'context_name' => $vdom_name,
'bgpPeerRemoteAddr' => $peer_ip
];
dbInsert($db_data, 'bgpPeers');
}
}
echo "Completed BGP discovery for VDOM: $vdom_name (Index: $vd_index)\n";
}
// Stop execution after FortiGate BGP discovery to prevent other BGP scripts from running
echo "BGP discovery for FortiGate (multi-VDOM) completed.\n";
exit;
/opt/librenms/includes/polling/bgp-peers.inc.php
<?php
use App\Models\Eventlog;
use Illuminate\Support\Str;
use LibreNMS\Enum\Severity;
use LibreNMS\Exceptions\InvalidIpException;
use LibreNMS\RRD\RrdDefinition;
use LibreNMS\Util\IP;
use LibreNMS\Util\Oid;
if ($device['os'] == 'fortigate') {
echo "Redirecting FortiGate BGP polling to fortigate-bgp-peers.inc.php\n";
include __DIR__ . '/fortigate-bgp-peers.inc.php';
return;
}
cat includes/polling/fortigate-bgp-peers.inc.php
<?php
d_echo("Polling FortiGate BGP peers...\n");
// Fetch all existing BGP peers from the database for this device
$existing_peers = dbFetchRows("SELECT bgpPeerIdentifier, context_name FROM `bgpPeers` WHERE device_id = ?", [$device['device_id']]);
if (empty($existing_peers)) {
d_echo("No existing BGP peers found in the database for this device. Exiting polling.\n");
return;
}
// Convert existing peers into a lookup array
$existing_peers_map = [];
foreach ($existing_peers as $peer) {
$existing_peers_map[$peer['bgpPeerIdentifier']] = $peer['context_name'];
}
// Fetch VDOMs (Virtual Domains) from the device
$vdoms = snmpwalk_cache_oid($device, 'fgVdEntName', [], 'FORTINET-FORTIGATE-MIB');
if (empty($vdoms)) {
d_echo("No VDOMs found. Skipping FortiGate BGP polling.\n");
return;
}
// Iterate over each VDOM
foreach ($vdoms as $vd_index => $vd) {
$vdom_name = $vd['fgVdEntName'];
d_echo("Polling BGP for VDOM: $vdom_name (Index: $vd_index)\n");
// Fetch BGP peers for this VDOM
$bgp_peers = snmpwalk_cache_oid($device, 'bgpPeerRemoteAs', [], 'BGP4-MIB');
if (empty($bgp_peers)) {
d_echo("No BGP peers found via SNMP for VDOM: $vdom_name. Skipping.\n");
continue;
}
// Fetch additional BGP attributes
$bgp_state = snmpwalk_cache_oid($device, 'bgpPeerState', [], 'BGP4-MIB');
$bgp_admin_status = snmpwalk_cache_oid($device, 'bgpPeerAdminStatus', [], 'BGP4-MIB');
$bgp_local_addr = snmpwalk_cache_oid($device, 'bgpPeerLocalAddr', [], 'BGP4-MIB');
$bgp_in_updates = snmpwalk_cache_oid($device, 'bgpPeerInUpdates', [], 'BGP4-MIB');
$bgp_out_updates = snmpwalk_cache_oid($device, 'bgpPeerOutUpdates', [], 'BGP4-MIB');
$bgp_in_messages = snmpwalk_cache_oid($device, 'bgpPeerInTotalMessages', [], 'BGP4-MIB');
$bgp_out_messages = snmpwalk_cache_oid($device, 'bgpPeerOutTotalMessages', [], 'BGP4-MIB');
$bgp_fsm_time = snmpwalk_cache_oid($device, 'bgpPeerFsmEstablishedTime', [], 'BGP4-MIB');
$bgp_update_elapsed = snmpwalk_cache_oid($device, 'bgpPeerInUpdateElapsedTime', [], 'BGP4-MIB');
// Process each peer and update only if it exists in the database
foreach ($bgp_peers as $peer_index => $peer) {
$peer_ip_full = $peer_index; // Example: "169.254.59.37.1"
// Remove last octet if it's a single number (VDOM index)
$peer_ip_parts = explode('.', $peer_ip_full);
if (count($peer_ip_parts) > 4) {
array_pop($peer_ip_parts); // Remove VDOM index
}
$peer_ip = implode('.', $peer_ip_parts); // Corrected peer IP
// Check if the peer exists in the database
if (!isset($existing_peers_map[$peer_ip])) {
d_echo("Skipping unknown BGP peer: $peer_ip (Not found in database)\n");
continue;
}
// Fetch additional SNMP values
$peer_state = $bgp_state[$peer_index]['bgpPeerState'] ?? 'idle';
$peer_admin = $bgp_admin_status[$peer_index]['bgpPeerAdminStatus'] ?? 'stop';
$peer_local_addr = $bgp_local_addr[$peer_index]['bgpPeerLocalAddr'] ?? '0.0.0.0';
$peer_in_updates = $bgp_in_updates[$peer_index]['bgpPeerInUpdates'] ?? 0;
$peer_out_updates = $bgp_out_updates[$peer_index]['bgpPeerOutUpdates'] ?? 0;
$peer_in_messages = $bgp_in_messages[$peer_index]['bgpPeerInTotalMessages'] ?? 0;
$peer_out_messages = $bgp_out_messages[$peer_index]['bgpPeerOutTotalMessages'] ?? 0;
$peer_fsm_time = $bgp_fsm_time[$peer_index]['bgpPeerFsmEstablishedTime'] ?? 0;
$peer_update_elapsed = $bgp_update_elapsed[$peer_index]['bgpPeerInUpdateElapsedTime'] ?? 0;
d_echo("Updating BGP peer: $peer_ip (AS{$peer['bgpPeerRemoteAs']}) in VDOM: $vdom_name\n");
// Update the database for this peer
dbUpdate([
'bgpPeerState' => $peer_state,
'bgpPeerAdminStatus' => $peer_admin,
'bgpLocalAddr' => $peer_local_addr,
'bgpPeerInUpdates' => $peer_in_updates,
'bgpPeerOutUpdates' => $peer_out_updates,
'bgpPeerInTotalMessages' => $peer_in_messages,
'bgpPeerOutTotalMessages' => $peer_out_messages,
'bgpPeerFsmEstablishedTime' => $peer_fsm_time,
'bgpPeerInUpdateElapsedTime' => $peer_update_elapsed,
], 'bgpPeers', 'device_id = ? AND bgpPeerIdentifier = ?', [
$device['device_id'],
$peer_ip
]);
d_echo("Updated BGP peer: $peer_ip in VDOM: $vdom_name\n");
}
}
d_echo("Completed FortiGate BGP polling.\n");
?>