Migrate xDSL code to module, and add support for VDSL2 MIB (#14207)

* use component to discover if xDSL polling is needed

use component to discover if xDSL polling is needed

* Components OK, Polling in correct files, no DB for VDSL

* GUI

GUI_suite

* per port as well

* rename

* interface listing

* draytek_snmpsim

* fix arraymerge

fix names and max value

* schema

schema

style

* remove one dbFetchRows

remove 2x dbFetchCell

style

style

remove Legacy dbFetchRow

tests

tests

eloquent

more eloquent

more eloquent

one more gone

* fix properties access

eloquent_insert_update

style

tests

tests

tests

tests

* tests

tests

tests

* adslLineCoding

* Models

* fix not nullable cols in DB from code

default values

typo

rename

typo

schema

fix

fix

vdsl fix now

typo

typo

fix size

fix size

* Power values for VDSL

Power values for VDSL

Power values for VDSL

DB

* cleanup

* Rrd::checkRrdExists

* always enable DSL discovery

style

* xdsl module

* cleanup and move to Module

cleanup and move to Module

cleanup and move to Module

cleanup and move to Module

* Fix display

* fix polling and tenth

* remove legacy poller

* Style and Cosmetics

Cosmetics

Cleanup

* Translations

Translations

* exists

exists

* add test support for xdsl

* remove last component call

unused

* translations

* remove non standard onclick event on xdsl line

* Update Discovery Support.md

Update Poller Support.md

toner_gone

* Notification for removal of lnms config:set enable_ports_adsl true

* enable on devices with potential DSL interfaces

* tests are working now

fix teldat tests

* os_schema

* teldat

* move to new module structure

* move to new module structure

* wrong dump function

* wrong dump function

* laravel_through_key hidden

* Update notifications.rss

* Update notifications.rss

Co-authored-by: Tony Murray <murraytony@gmail.com>
This commit is contained in:
PipoCanaja
2022-09-08 02:29:17 +02:00
committed by GitHub
parent b44f1546a2
commit 53bfb24ef9
56 changed files with 4079 additions and 278 deletions

View File

@@ -0,0 +1,25 @@
<?php
$rrd_filename = get_port_rrdfile_path($device['hostname'], $port['port_id'], 'xdsl2LineStatusAttainableRate');
$rrd_list[0]['filename'] = $rrd_filename;
$rrd_list[0]['descr'] = 'Central to CPE';
$rrd_list[0]['ds'] = 'ds';
$rrd_list[1]['filename'] = $rrd_filename;
$rrd_list[1]['descr'] = 'CPE to Central';
$rrd_list[1]['ds'] = 'us';
$unit_text = 'Bits/sec';
$units = '';
$total_units = '';
$colours = 'mixed';
$scale_min = '0';
$nototal = 1;
if ($rrd_list) {
include 'includes/html/graphs/generic_multi_line.inc.php';
}

View File

@@ -0,0 +1,25 @@
<?php
$rrd_filename = get_port_rrdfile_path($device['hostname'], $port['port_id'], 'xdsl2LineStatusActAtp');
$rrd_list[0]['filename'] = $rrd_filename;
$rrd_list[0]['descr'] = 'Central to CPE';
$rrd_list[0]['ds'] = 'ds';
$rrd_list[1]['filename'] = $rrd_filename;
$rrd_list[1]['descr'] = 'CPE to Central';
$rrd_list[1]['ds'] = 'us';
$unit_text = 'Dbm';
$units = '';
$total_units = '';
$colours = 'mixed';
$scale_min = '0';
$nototal = 1;
if ($rrd_list) {
include 'includes/html/graphs/generic_multi_line.inc.php';
}

View File

@@ -0,0 +1,25 @@
<?php
$rrd_filename = get_port_rrdfile_path($device['hostname'], $port['port_id'], 'xdsl2ChStatusActDataRate');
$rrd_list[0]['filename'] = $rrd_filename;
$rrd_list[0]['descr'] = 'Central to CPE';
$rrd_list[0]['ds'] = 'xtur';
$rrd_list[1]['filename'] = $rrd_filename;
$rrd_list[1]['descr'] = 'CPE to Central';
$rrd_list[1]['ds'] = 'xtuc';
$unit_text = 'Bits/sec';
$units = '';
$total_units = '';
$colours = 'mixed';
$scale_min = '0';
$nototal = 1;
if ($rrd_list) {
include 'includes/html/graphs/generic_multi_line.inc.php';
}

View File

@@ -1,5 +1,9 @@
<?php
use App\Models\Device;
use App\Models\Port;
use App\Models\PortAdsl;
use App\Models\PortVdsl;
use App\Plugins\Hooks\PortTabHook;
use LibreNMS\Util\Rewrite;
use LibreNMS\Util\Url;
@@ -81,11 +85,13 @@ if (dbFetchCell("SELECT COUNT(*) FROM `sensors` WHERE `device_id` = ? AND `entPh
$menu_options['sensors'] = 'Health';
}
if (dbFetchCell("SELECT COUNT(*) FROM `ports_adsl` WHERE `port_id` = '" . $port->port_id . "'")) {
$menu_options['adsl'] = 'ADSL';
if (PortAdsl::where('port_id', $port->port_id)->exists()) {
$menu_options['xdsl'] = 'xDSL';
} elseif (PortVdsl::where('port_id', $port->port_id)->exists()) {
$menu_options['xdsl'] = 'xDSL';
}
if (dbFetchCell("SELECT COUNT(*) FROM `ports` WHERE `pagpGroupIfIndex` = '" . $port->ifIndex . "' and `device_id` = '" . $device['device_id'] . "'")) {
if (DeviceCache::getPrimary()->ports()->where('pagpGroupIfIndex', $port->ifIndex)->exists()) {
$menu_options['pagp'] = 'PAgP';
}
@@ -103,7 +109,7 @@ if (count($components) > 0) {
$menu_options['cbqos'] = 'CBQoS';
}
$portModel = \App\Models\Port::find($port->port_id);
$portModel = Port::find($port->port_id);
if (LibreNMS\Plugins::countHooks('port_container') || \PluginManager::hasHooks(PortTabHook::class, ['port' => $portModel])) {
// Checking if any plugin implements the port_container. If yes, allow to display the menu_option

View File

@@ -1,6 +1,6 @@
<?php
if (file_exists(get_port_rrdfile_path($device['hostname'], $port['port_id'], 'adsl'))) {
if (Rrd::checkRrdExists(Rrd::name($device['hostname'], Rrd::portName($port['port_id'], 'adsl')))) {
echo '<div class=graphhead>ADSL Current Line Speed</div>';
$graph_type = 'port_adsl_speed';
@@ -26,3 +26,20 @@ if (file_exists(get_port_rrdfile_path($device['hostname'], $port['port_id'], 'ad
include 'includes/html/print-interface-graphs.inc.php';
}
if (Rrd::checkRrdExists(Rrd::name($device['hostname'], Rrd::portName($port['port_id'], 'xdsl2LineStatusAttainableRate')))) {
echo '<div class=graphhead>VDSL Current Line Speed</div>';
$graph_type = 'port_vdsl_speed';
include 'includes/html/print-interface-graphs.inc.php';
echo '<div class=graphhead>VDSL Attainable Speed</div>';
$graph_type = 'port_vdsl_attainable';
include 'includes/html/print-interface-graphs.inc.php';
echo '<div class=graphhead>VDSL Output Powers</div>';
$graph_type = 'port_vdsl_power';
include 'includes/html/print-interface-graphs.inc.php';
}

View File

@@ -33,8 +33,8 @@ if (dbFetchCell("SELECT * FROM links AS L, ports AS I WHERE I.device_id = '" . $
$menu_options['neighbours'] = 'Neighbours';
}
if (dbFetchCell("SELECT COUNT(*) FROM `ports` WHERE `ifType` = 'adsl'")) {
$menu_options['adsl'] = 'ADSL';
if (DeviceCache::getPrimary()->portsAdsl()->exists() || DeviceCache::getPrimary()->portsVdsl()->exists()) {
$menu_options['xdsl'] = 'xDSL';
}
$sep = '';
@@ -123,7 +123,7 @@ if ($vars['view'] == 'minigraphs') {
}
echo '</div>';
} elseif ($vars['view'] == 'arp' || $vars['view'] == 'adsl' || $vars['view'] == 'neighbours' || $vars['view'] == 'fdb') {
} elseif ($vars['view'] == 'arp' || $vars['view'] == 'xdsl' || $vars['view'] == 'neighbours' || $vars['view'] == 'fdb') {
include 'ports/' . $vars['view'] . '.inc.php';
} else {
if ($vars['view'] == 'details') {

View File

@@ -1,15 +0,0 @@
<?php
echo "<div style='margin: 5px;'><table border=0 cellspacing=0 cellpadding=5 width=100%>";
echo '<tr><th>Port</th><th>Traffic</th><th>Sync Speed</th><th>Attainable Speed</th><th>Attenuation</th><th>SNR Margin</th><th>Output Powers</th></tr>';
$i = '0';
$ports = dbFetchRows("select * from `ports` AS P, `ports_adsl` AS A WHERE P.device_id = ? AND A.port_id = P.port_id AND P.deleted = '0' ORDER BY `ifIndex` ASC", [$device['device_id']]);
foreach ($ports as $port) {
include 'includes/html/print-interface-adsl.inc.php';
$i++;
}
echo '</table></div>';
echo "<div style='min-height: 150px;'></div>";

View File

@@ -0,0 +1,28 @@
<?php
echo "<div style='margin: 5px;'><table border=0 cellspacing=0 cellpadding=5 width=100%>";
echo '<tr><th>Port</th><th>Traffic</th><th>Sync Speed</th><th>Attainable Speed</th><th>Attenuation</th><th>SNR Margin</th><th>Output Powers</th></tr>';
$i = '0';
$ports = DeviceCache::getPrimary()->ports()->join('ports_adsl', 'ports.port_id', 'ports_adsl.port_id')
->where('ports.deleted', '0')
->orderby('ports.ifIndex', 'ASC')
->get();
foreach ($ports as $port) {
include 'includes/html/print-interface-adsl.inc.php';
$i++;
}
$ports = DeviceCache::getPrimary()->ports()->join('ports_vdsl', 'ports.port_id', '=', 'ports_vdsl.port_id')
->where('ports.deleted', '0')
->orderby('ports.ifIndex', 'ASC')
->get();
foreach ($ports as $port) {
include 'includes/html/print-interface-vdsl.inc.php';
$i++;
}
echo '</table></div>';
echo "<div style='min-height: 150px;'></div>";

View File

@@ -13,6 +13,7 @@
* @author LibreNMS Contributors
*/
use App\Models\Device;
use App\Models\Port;
use Illuminate\Database\Eloquent\ModelNotFoundException;
@@ -92,11 +93,11 @@ if ((isset($vars['searchbar']) && $vars['searchbar'] != 'hide') || ! isset($vars
$output .= "<select name='device_id' id='device_id' class='form-control input-sm'>";
$output .= "<option value=''>All Devices</option>";
if (Auth::user()->hasGlobalRead()) {
$results = dbFetchRows('SELECT `device_id`,`hostname`, `sysName` FROM `devices` ORDER BY `hostname`');
} else {
$results = dbFetchRows('SELECT `D`.`device_id`,`D`.`hostname`, `D`.`sysname` FROM `devices` AS `D`, `devices_perms` AS `P` WHERE `P`.`user_id` = ? AND `P`.`device_id` = `D`.`device_id` ORDER BY `hostname`', [Auth::id()]);
}
// if (Auth::user()->hasGlobalRead()) {
$results = Device::hasAccess(Auth::user())->select('device_id', 'hostname', 'sysName')->orderBy('hostname');
// } else {
// $results = dbFetchRows('SELECT `D`.`device_id`,`D`.`hostname`, `D`.`sysname` FROM `devices` AS `D`, `devices_perms` AS `P` WHERE `P`.`user_id` = ? AND `P`.`device_id` = `D`.`device_id` ORDER BY `hostname`', [Auth::id()]);
// }
foreach ($results as $data) {
$deviceselected = isset($vars['device_id']) && $data['device_id'] == $vars['device_id'] ? 'selected' : '';
$ui_device = strlen(format_hostname($data)) > 15 ? substr(format_hostname($data), 0, 15) . '...' : format_hostname($data);

View File

@@ -23,8 +23,7 @@ if ($port['ifInErrors_delta'] > 0 || $port['ifOutErrors_delta'] > 0) {
$error_img = '';
}
echo "<tr style=\"background-color: $row_colour; padding: 5px;\" valign=top onmouseover=\"this.style.backgroundColor='" . Config::get('list_colour.highlight') . "';\" onmouseout=\"this.style.backgroundColor='$row_colour';\"
onclick=\"location.href='device/" . $device['device_id'] . '/port/' . $port['port_id'] . "/'\" style='cursor: pointer;'>
echo "<tr style=\"background-color: $row_colour; padding: 5px;\" valign=top onmouseover=\"this.style.backgroundColor='" . Config::get('list_colour.highlight') . "';\" onmouseout=\"this.style.backgroundColor='$row_colour';\" style='cursor: pointer;'>
<td valign=top width=350>";
echo ' <span class=list-large>
' . generate_port_link($port, $port['ifIndex'] . '. ' . $port['label']) . '
@@ -64,7 +63,7 @@ echo generate_port_link(
);
echo '</td><td width=135>';
echo '' . \LibreNMS\Util\Number::formatSi($port['adslAturChanCurrTxRate'], 2, 3, 'bps') . '/' . \LibreNMS\Util\Number::formatSi($port['adslAtucChanCurrTxRate'], 2, 3, 'bps');
echo '' . \LibreNMS\Util\Number::formatSi($port['adslAtucChanCurrTxRate'], 2, 3, 'bps') . '/' . \LibreNMS\Util\Number::formatSi($port['adslAturChanCurrTxRate'], 2, 3, 'bps');
echo '<br />';
$port['graph_type'] = 'port_adsl_speed';
echo generate_port_link(

View File

@@ -0,0 +1,117 @@
<?php
// This file prints a table row for each interface
use app\Models\Ipv4Address;
use app\Models\Ipv6Address;
use LibreNMS\Config;
use LibreNMS\Util\IP;
$port['device_id'] = $device['device_id'];
$port['hostname'] = $device['hostname'];
$if_id = $port['port_id'];
$port = cleanPort($port);
if (! is_integer($i / 2)) {
$row_colour = Config::get('list_colour.even');
} else {
$row_colour = Config::get('list_colour.odd');
}
if ($port['ifInErrors_delta'] > 0 || $port['ifOutErrors_delta'] > 0) {
$error_img = generate_port_link($port, "<i class='fa fa-flag fa-lg' style='color:red' aria-hidden='true'></i>", 'port_errors');
} else {
$error_img = '';
}
echo "<tr style=\"background-color: $row_colour; padding: 5px;\" valign=top onmouseover=\"this.style.backgroundColor='" . Config::get('list_colour.highlight') . "';\" onmouseout=\"this.style.backgroundColor='$row_colour';\" style='cursor: pointer;'>
<td valign=top width=350>";
echo ' <span class=list-large>
' . generate_port_link($port, $port['ifIndex'] . '. ' . $port['label']) . '
</span><br /><span class=interface-desc>' . \LibreNMS\Util\Clean::html($port['ifAlias'], []) . '</span>';
if ($port['ifAlias']) {
echo '<br />';
}
$break = '';
if ($port_details) {
foreach (Ipv4Address::where('port_id', (string) $port['port_id']) as $ip) {
echo "$break <a class=interface-desc href=\"javascript:popUp('ajax/netcmd?cmd=whois&amp;query=" . $ip['ipv4_address'] . "')\">" . $ip['ipv4_address'] . '/' . $ip['ipv4_prefixlen'] . '</a>';
$break = ',';
}
foreach (Ipv6Address::where('port_id', (string) $port['port_id']) as $ip6) {
echo "$break <a class=interface-desc href=\"javascript:popUp('ajax/netcmd?cmd=whois&amp;query=" . $ip6['ipv6_address'] . "')\">" . IP::parse($ip6['ipv6_address'], true) . '/' . $ip6['ipv6_prefixlen'] . '</a>';
$break = ',';
}
}
echo '</span>';
$width = '120';
$height = '40';
$from = Config::get('time.day');
echo '</td><td width=135>';
echo \LibreNMS\Util\Number::formatSi(($port['ifInOctets_rate'] * 8), 2, 3, 'bps') . " <i class='fa fa-arrows-v fa-lg icon-theme' aria-hidden='true'></i> " . \LibreNMS\Util\Number::formatSi(($port['ifOutOctets_rate'] * 8), 2, 3, 'bps');
echo '<br />';
$port['graph_type'] = 'port_bits';
echo generate_port_link(
$port,
"<img src='graph.php?type=" . $port['graph_type'] . '&amp;id=' . $port['port_id'] . '&amp;from=' . $from . '&amp;to=' . Config::get('time.now') . '&amp;width=' . $width . '&amp;height=' . $height . '&amp;legend=no&amp;bg=' . str_replace('#', '', $row_colour) . "'>",
$port['graph_type']
);
echo '</td><td width=135>';
echo '' . \LibreNMS\Util\Number::formatSi($port['xdsl2ChStatusActDataRateXtur'], 2, 3, 'bps') . '/' . \LibreNMS\Util\Number::formatSi($port['xdsl2ChStatusActDataRateXtuc'], 2, 3, 'bps');
echo '<br />';
$port['graph_type'] = 'port_vdsl_speed';
echo generate_port_link(
$port,
"<img src='graph.php?type=" . $port['graph_type'] . '&amp;id=' . $port['port_id'] . '&amp;from=' . $from . '&amp;to=' . Config::get('time.now') . '&amp;width=' . $width . '&amp;height=' . $height . '&amp;legend=no&amp;bg=' . str_replace('#', '', $row_colour) . "'>",
$port['graph_type']
);
echo '</td><td width=135>';
echo '' . \LibreNMS\Util\Number::formatSi($port['xdsl2LineStatusAttainableRateDs'], 2, 3, 'bps') . '/' . \LibreNMS\Util\Number::formatSi($port['xdsl2LineStatusAttainableRateUs'], 2, 3, 'bps');
echo '<br />';
$port['graph_type'] = 'port_vdsl_attainable';
echo generate_port_link(
$port,
"<img src='graph.php?type=" . $port['graph_type'] . '&amp;id=' . $port['port_id'] . '&amp;from=' . $from . '&amp;to=' . Config::get('time.now') . '&amp;width=' . $width . '&amp;height=' . $height . '&amp;legend=no&amp;bg=' . str_replace('#', '', $row_colour) . "'>",
$port['graph_type']
);
echo '</td><td width=135>';
//echo '' . $port['adslAturCurrAtn'] . 'dB/' . $port['adslAtucCurrAtn'] . 'dB';
//echo '<br />';
//$port['graph_type'] = 'port_adsl_attenuation';
//echo generate_port_link(
// $port,
// "<img src='graph.php?type=" . $port['graph_type'] . '&amp;id=' . $port['port_id'] . '&amp;from=' . $from . '&amp;to=' . Config::get('time.now') . '&amp;width=' . $width . '&amp;height=' . $height . '&amp;legend=no&amp;bg=' . str_replace('#', '', $row_colour) . "'>",
// $port['graph_type']
//);
echo '</td><td width=135>';
//echo '' . $port['adslAturCurrSnrMgn'] . 'dB/' . $port['adslAtucCurrSnrMgn'] . 'dB';
//echo '<br />';
//$port['graph_type'] = 'port_adsl_snr';
//echo generate_port_link(
// $port,
// "<img src='graph.php?type=" . $port['graph_type'] . '&amp;id=' . $port['port_id'] . '&amp;from=' . $from . '&amp;to=' . Config::get('time.now') . '&amp;width=' . $width . '&amp;height=' . $height . '&amp;legend=no&amp;bg=' . str_replace('#', '', $row_colour) . "'>",
// $port['graph_type']
//);
echo '</td><td width=135>';
echo '' . $port['xdsl2LineStatusActAtpDs'] . 'dBm/' . $port['xdsl2LineStatusActAtpUs'] . 'dBm';
echo '<br />';
$port['graph_type'] = 'port_vdsl_power';
echo generate_port_link(
$port,
"<img src='graph.php?type=" . $port['graph_type'] . '&amp;id=' . $port['port_id'] . '&amp;from=' . $from . '&amp;to=' . Config::get('time.now') . '&amp;width=' . $width . '&amp;height=' . $height . '&amp;legend=no&amp;bg=' . str_replace('#', '', $row_colour) . "'>",
$port['graph_type']
);
echo '</td>';

View File

@@ -6,6 +6,8 @@ $(function () {
<?php
use App\Models\Port;
use App\Models\PortAdsl;
use App\Models\PortVdsl;
use LibreNMS\Config;
use LibreNMS\Util\IP;
use LibreNMS\Util\Number;
@@ -30,7 +32,8 @@ if (isset($int_colour)) {
$i++;
}
$port_adsl = dbFetchRow('SELECT * FROM `ports_adsl` WHERE `port_id` = ?', [$port['port_id']]);
$port_adsl = PortAdsl::where('port_id', '=', $port['port_id']);
$port_vdsl = PortVdsl::where('port_id', '=', $port['port_id']);
if ($port['ifInErrors_delta'] > 0 || $port['ifOutErrors_delta'] > 0) {
$error_img = generate_port_link($port, "<i class='fa fa-flag fa-lg' style='color:red' aria-hidden='true'></i>", 'port_errors');
@@ -141,22 +144,30 @@ if ($vlan_count > 1) {
echo "<p style='color: green;'>" . $vrf['vrf_name'] . '</p>';
}//end if
if (! empty($port_adsl['adslLineCoding'])) {
if (! empty($port_adsl->adslLineCoding)) {
echo "</td><td width=150 onclick=\"location.href='" . generate_port_url($port) . "'\" >";
echo $port_adsl['adslLineCoding'] . '/' . rewrite_adslLineType($port_adsl['adslLineType']);
echo $port_adsl->adslLineCoding . '/' . rewrite_adslLineType($port_adsl->adslLineType);
echo '<br />';
// ATU-C is CO -> ATU-C TX is the download speed for the CPE
// ATU-R is the CPE -> ATU-R TX is the upload speed of the CPE
echo 'Sync:' . Number::formatSi($port_adsl['adslAtucChanCurrTxRate'], 2, 3, 'bps') . '/' . Number::formatSi($port_adsl['adslAturChanCurrTxRate'], 2, 3, 'bps');
echo 'Sync:' . Number::formatSi($port_adsl->adslAtucChanCurrTxRate, 2, 3, 'bps') . '/' . Number::formatSi($port_adsl->adslAturChanCurrTxRate, 2, 3, 'bps');
echo '<br />';
// This is the Receive Max AttainableRate, so :
// adslAturCurrAttainableRate is DownloadMaxRate
// adslAtucCurrAttainableRate is UploadMaxRate
echo 'Max:' . Number::formatSi($port_adsl['adslAturCurrAttainableRate'], 2, 3, 'bps') . '/' . Number::formatSi($port_adsl['adslAtucCurrAttainableRate'], 2, 3, 'bps');
echo 'Max:' . Number::formatSi($port_adsl->adslAturCurrAttainableRate, 2, 3, 'bps') . '/' . Number::formatSi($port_adsl->adslAtucCurrAttainableRate, 2, 3, 'bps');
echo "</td><td width=150 onclick=\"location.href='" . generate_port_url($port) . "'\" >";
echo 'Atten:' . $port_adsl['adslAturCurrAtn'] . 'dB/' . $port_adsl['adslAtucCurrAtn'] . 'dB';
echo 'Atten:' . $port_adsl->adslAturCurrAtn . 'dB/' . $port_adsl->adslAtucCurrAtn . 'dB';
echo '<br />';
echo 'SNR:' . $port_adsl['adslAturCurrSnrMgn'] . 'dB/' . $port_adsl['adslAtucCurrSnrMgn'] . 'dB';
echo 'SNR:' . $port_adsl->adslAturCurrSnrMgn . 'dB/' . $port_adsl->adslAtucCurrSnrMgn . 'dB';
} elseif (! empty($port_vdsl->xdsl2LineStatusAttainableRateDs)) {
echo "</td><td width=150 onclick=\"location.href='" . generate_port_url($port) . "'\" >";
echo '<br />';
// ATU-C is CO -> ATU-C TX is the download speed for the CPE
// ATU-R is the CPE -> ATU-R TX is the upload speed of the CPE
echo 'Sync:' . Number::formatSi($port_vdsl->xdsl2ChStatusActDataRateXtur, 2, 3, 'bps') . '/' . Number::formatSi($port_vdsl->xdsl2ChStatusActDataRateXtuc, 2, 3, 'bps');
echo '<br />';
echo 'Max:' . Number::formatSi($port_vdsl->xdsl2LineStatusAttainableRateDs, 2, 3, 'bps') . '/' . Number::formatSi($port_vdsl->xdsl2LineStatusAttainableRateUs, 2, 3, 'bps');
} else {
echo "</td><td width=150 onclick=\"location.href='" . generate_port_url($port) . "'\" >";
if ($port['ifType'] && $port['ifType'] != '') {