Mpls Path Visualization (#10936)

* update nokia mibs

* database migrations

* add code

* html code

* update db schema

* add test data

* add FIXME

* move mibs/nokia/MPLS-TE-MIB to mibs/MPLS-TE-MIB
This commit is contained in:
Vitali Kari
2020-01-01 23:45:06 +01:00
committed by PipoCanaja
parent ef01aba878
commit 532ab1127a
37 changed files with 96711 additions and 33539 deletions

View File

@@ -154,7 +154,8 @@ if ($vars['view'] == 'lsp') {
} // endif lsp view
if ($vars['view'] == 'paths') {
echo '<tr><th><a title="Administrative name for LSP this path belongs to">LSP Name</a></th>
echo '<tr><th>&nbsp;</th>
<th><a title="Administrative name for LSP this path belongs to">LSP Name</a></th>
<th><a title="The OID index of this path">Index</a></th>
<th><a title="This variable is an enum that represents the role this path is taking within this LSP.">Type</a></th>
<th><a title="The desired administrative state for this LSP Path.">Admin State</a></th>
@@ -195,12 +196,13 @@ if ($vars['view'] == 'paths') {
}
$host = @dbFetchRow('SELECT * FROM `ipv4_addresses` AS A, `ports` AS I, `devices` AS D WHERE A.ipv4_address = ? AND I.port_id = A.port_id AND D.device_id = I.device_id', [$path['mplsLspPathFailNodeAddr']]);
$destination = $lsp['mplsLspPathFailNodeAddr'];
$destination = $path['mplsLspPathFailNodeAddr'];
if (is_array($host)) {
$destination = generate_device_link($host, 0, array('tab' => 'routing', 'proto' => 'mpls'));
}
echo "<tr bgcolor=$bg_colour>
<td>" . $path['mplsLspName'] . '</td>
echo '<tr data-toggle="collapse" data-target="#path-map' . $i . '" class="accordion-toggle" bgcolor="' . $bg_colour .'">
<td><button class="btn btn-default btn-xs"><span class="fa fa-plus"></span></button></td>
<td>' . $path['mplsLspName'] . '</td>
<td>' . $path['path_oid'] . '</td>
<td>' . $path['mplsLspPathType'] . '</td>
<td><span class="label label-' . $adminstate_status_color . '">' . $path['mplsLspPathAdminState'] . '</td>
@@ -215,6 +217,13 @@ if ($vars['view'] == 'paths') {
<td>' . $path['mplsLspPathMetric'] . '</td>
<td>' . $path['mplsLspPathOperMetric'] . '</td>';
echo '</tr>';
echo '<tr><td colspan="12" class="hiddenRow">';
echo '<div class="accordian-body collapse" id="path-map' . $i . '">';
// FIXME include only on expanded data-toggle
include 'includes/html/pages/routing/mpls-path-map.inc.php';
echo '</div>
</td>
</tr>';
$i++;
}

View File

@@ -0,0 +1,195 @@
<?php
/*
* LibreNMS
*
* Copyright (c) 2019 Vitali Kari
*
* 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. Please see LICENSE.txt at the top level of
* the source code distribution for details.
*/
use LibreNMS\Config;
use Illuminate\Support\Collection;
$hops = [];
$links =[];
$options = Config::get('network_map_vis_options');
$lsp_path_id = $path['lsp_path_id'];
$last_node = dbFetchCell('SELECT L.mplsLspToAddr FROM mpls_lsps AS L, mpls_lsp_paths AS P WHERE P.lsp_path_id = ? AND L.lsp_id = P.lsp_id', [$path['lsp_path_id']]);
$device_id = $device['device_id'];
$ar_list = dbFetchRows('SELECT * from `mpls_tunnel_ar_hops` where device_id = ? AND lsp_path_id = ?', [$device_id, $lsp_path_id]);
d_echo($ar_list);
// first node is host self
$node = device_has_ip($ar_list[0]['mplsTunnelARHopRouterId']);
if ($node) {
$node_id = $node['device_id'];
$label = $node['hostname'];
$first_node = $ar_list[0]['mplsTunnelARHopRouterId'];
} else {
$node_id = $label = $first_node;
}
foreach ($ar_list as $value) {
$node = device_has_ip($value['mplsTunnelARHopRouterId']);
if ($node) {
$remote_node_id = $node['device_id'];
$remote_label = $node['hostname'];
} else {
$remote_node_id = $remote_label = $value['mplsTunnelARHopRouterId'];
}
$hops[$remote_node_id] = [
'id' => $remote_node_id,
'label' => $remote_label . PHP_EOL . $value['mplsTunnelARHopRouterId'],
];
if ($value['nextNodeProtected'] == 'true') {
$hops[$remote_node_id]['color'] = '#ccffcc';
$hops[$remote_node_id]['title'] = 'Node Protected';
} else {
$hops[$remote_node_id]['color'] = '#cccccc';
$hops[$remote_node_id]['title'] = 'Node Not Protected';
}
if ($value['mplsTunnelARHopRouterId'] == $first_node || $value['mplsTunnelARHopRouterId'] == $last_node) {
$hops[$remote_node_id]['shape'] = 'circle';
}
$lsp = dbFetchCell('SELECT L.mplsLspName FROM mpls_lsps AS L, mpls_lsp_paths AS P WHERE P.lsp_path_id = ? AND L.lsp_id = P.lsp_id', [$value['lsp_path_id']]);
if ($value['localProtected'] == 'true') {
$link_color = '#004d00';
} else {
$link_color = '#000000';
}
$links[] = [
'from' => $node_id,
'to' => $remote_node_id,
'label' => strval($value['mplsTunnelARHopIpv4Addr']),
'font' =>
[
'align' => 'top',
'color' => $link_color,
],
'title' => $lsp . ' active hop #' . strval($value['mplsTunnelARHopIndex']) . ' Link Protected: ' . $value['localProtected'],
'width' => 4.0,
'color' =>
[
'color' => $link_color,
'opacity' => '0.6',
],
'selfReferenceSize' => 45,
];
// process next hop
$node_id = $remote_node_id;
$label = $remote_label;
}
// try to find the computed CSPF Path
$dev_mpls_tunnel_c_hops = collect(dbFetchRows('SELECT * FROM mpls_tunnel_c_hops where device_id = ?', [$device_id])); // collect all computed hops
$keyed = $dev_mpls_tunnel_c_hops->keyBy('mplsTunnelCHopListIndex'); // reduce to last hops
// Filter to only with final destination
$filtered = $keyed->filter(function ($value) use ($last_node) {
return ($value['mplsTunnelCHopRouterId'] == $last_node);
});
// FIXME pick the last one, but it seems that the secod one could work too. On NOKIA it actually does not matter, the paths have the same hops.
// The first one is the active route path.
$filtered2 = $filtered->last()['mplsTunnelCHopListIndex'];
// get CSPF List
$c_list = dbFetchRows('SELECT * from `mpls_tunnel_c_hops` where device_id = ? AND mplsTunnelCHopListIndex = ?', [$device_id, $filtered2]);
// first node is host self
$node = device_has_ip($c_list[0]['mplsTunnelCHopRouterId']);
if ($node) {
$node_id = $node['device_id'];
$label = $node['hostname'];
} else {
$node_id = $label = $c_list[0]['mplsTunnelCHopRouterId'];
}
foreach ($c_list as $value) {
$node = device_has_ip($value['mplsTunnelCHopRouterId']);
if ($node) {
$remote_node_id = $node['device_id'];
$remote_label = $node['hostname'];
} else {
$remote_node_id = $remote_label = $value['mplsTunnelCHopRouterId'];
}
if (empty($hops[$remote_node_id])) {
$hops[$remote_node_id] = [
'id' => $remote_node_id,
'label' => $remote_label . PHP_EOL . $value['mplsTunnelCHopRouterId'],
'color' => '#cccccc',
'title' => 'Node Protection Unknown',
];
}
$links[] = [
'from' => $node_id,
'to' => $remote_node_id,
'label' => strval($value['mplsTunnelCHopIpv4Addr']),
'font' =>
[
'align' => 'bottom',
'color' => '#262626',
],
'title' => 'computed detour hop # ' . strval($value['mplsTunnelCHopIndex']),
'width' => 4.0,
'color' =>
[
'color' => '#262626',
'opacity' => '0.5',
],
'selfReferenceSize' => 25,
'dashes' => 'true',
];
// process next hop
$node_id = $remote_node_id;
$label = $remote_label;
}
$nodes = json_encode(array_values($hops));
$edges = json_encode($links);
if (count($hops) > 1 && count($links) > 0) {
$visualization = 'visualization-' . $i;
echo '<div id="visualization-' . $i . '"></div>
<script src="js/vis.min.js"></script>
<script type="text/javascript">
var height = $(window).height() / 2;
';
echo "$('#" . $visualization . "').height(height + 'px');
var nodes = " . $nodes . ";
var edges = " . $edges . ";
";
echo "var container = document.getElementById('" . $visualization . "');
";
echo "var data = {
nodes: nodes,
edges: edges,
stabilize: true
};
var options = " . $options . ";
";
echo "var network = new vis.Network(container, data, options);
network.on('click', function (properties) {
if (properties.nodes > 0) {
window.location.href = " . '"device/device="+properties.nodes+"/tab=routing/proto=mpls/view=paths/"
}
});
</script>';
} else {
print_message("No Path map to display. Maybe there are no MPLS tunnel hops discovered.");
}

View File

@@ -199,12 +199,12 @@ if ($vars['view'] == 'paths') {
}
$host = @dbFetchRow('SELECT * FROM `ipv4_addresses` AS A, `ports` AS I, `devices` AS D WHERE A.ipv4_address = ? AND I.port_id = A.port_id AND D.device_id = I.device_id', [$path['mplsLspPathFailNodeAddr']]);
$destination = $lsp['mplsLspPathFailNodeAddr'];
$destination = $path['mplsLspPathFailNodeAddr'];
if (is_array($host)) {
$destination = generate_device_link($host, 0, array('tab' => 'routing', 'proto' => 'mpls'));
}
echo "<tr bgcolor=$bg_colour>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls')) . '</td>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls', 'view' => 'paths')) . '</td>
<td>' . $path['mplsLspName'] . '</td>
<td>' . $path['path_oid'] . '</td>
<td>' . $path['mplsLspPathType'] . '</td>
@@ -269,7 +269,7 @@ if ($vars['view'] == 'sdps') {
$destination = generate_device_link($host, 0, array('tab' => 'routing', 'proto' => 'mpls'));
}
echo "<tr bgcolor=$bg_colour>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls')) . '</td>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls', 'view' => 'sdps')) . '</td>
<td>' . $sdp['sdp_oid'] . '</td>
<td>' . $destination . '</td>
<td>' . $sdp['sdpDelivery'] . '</td>
@@ -337,7 +337,7 @@ sapDown: The SAP associated with the service is down.">Oper State</a></th>
}
echo "<tr bgcolor=$bg_colour>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls')) . '</td>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls', 'view' => 'sdpbinds')) . '</td>
<td>' . $sdpbind['svcId'] . '</td>
<td>' . $sdpbind['sdp_oid'] . ':' . $sdpbind['svc_oid'] . '</td>
<td>' . $sdpbind['sdpBindType'] . '</td>
@@ -405,7 +405,7 @@ vprn services are up when the service is administratively up however routing fun
}
echo "<tr bgcolor=$bg_colour>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls')) . '</td>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls', 'view' => 'services')) . '</td>
<td>' . $svc['svc_oid'] . '</td>
<td>' . $svc['svcType'] . '</td>
<td>' . $svc['svcCustId'] . '</td>
@@ -468,7 +468,7 @@ if ($vars['view'] == 'saps') {
}
echo "<tr bgcolor=$bg_colour>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls')) . '</td>
<td>" . generate_device_link($device, 0, array('tab' => 'routing', 'proto' => 'mpls', 'view' => 'saps')) . '</td>
<td>' . $sap['svc_oid'] . '</td>
<td>' . generate_port_link($port) . '</td>
<td>' . $sap['sapEncapValue'] . '</td>