Files
RTLPlayground/html/ports.js
T
d00f 38b8e38c04 ports: show the SFP port in the table, and read the right link state
The port table skipped every SFP port outright, so on a SWTGW218AS the
uplink simply was not there. Of the seven columns only Set Speed is
meaningless for a module: the name, the link speed and the devices behind
the port all are worth showing, and the name in particular was accepted on
another page and then never displayed anywhere. The MTU table further down
the same page has always drawn the port, so the page disagreed with itself.

Give an SFP port its row and leave the three control cells empty. Whether
speed and disable should work for a module is a separate question and
untested, so this does not offer a button for it.

The link state was read one port too far. main.js fills pState by
portNum - 1, updatePortTable() reads pState[i-1], and createPortTable()
read pState[i], so every row started out showing the next port's link
speed until the first refresh corrected it. On the last copper port that
meant showing the uplink's speed. Feeding the real status.json of a nine
port switch through both versions:

  expected  7  7  7  1  7  1  7  7  6
  before    7  7  1  7  1  7  7  6
  after     7  7  7  1  7  1  7  7  6

Dropping the skip also removes a trap rather than papering over it.
updatePortTable() addresses rows as tbl.rows[i], which only lined up with
port i because the SFP port happens to be last on this board. With a
module in the middle every row after it would have been off by one.
2026-09-06 00:09:22 +02:00

191 lines
6.2 KiB
JavaScript

var mtus = new Int16Array(10);
var clicked = new Int8Array(10);
function createPortTable() {
var tbl = document.getElementById('speedtable');
if (tbl.rows.length <= 2 && numPorts) {
const sSelect = '<select name="speed_sel" id="speed_sel">'
+ '<option value="auto">' + t('port_auto') + '</option>'
+ '<option value="2g5">' + t('port_2500m') + '</option>'
+ '<option value="1g">' + t('port_1000m') + '</option>'
+ '<option value="100m full">' + t('port_100m_f') + '</option>'
+ '<option value="100m half">' + t('port_100m_h') + '</option>'
+ '<option value="10m full">' + t('port_10m_f') + '</option>'
+ '<option value="10m half">' + t('port_10m_h') + '</option>'
+ '</select>';
const dSwitch = '<input type="checkbox" id="disable_port" onchange="portOnOff();">'
for (let i = 1; i <= numPorts; i++) {
const tr = tbl.insertRow();
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + i));
let portName = portNames[physToLogPort[i-1]] || '';
td = tr.insertCell(); td.appendChild(document.createTextNode(portName));
td = tr.insertCell(); td.innerHTML = linkText(pState[i-1] + 1);
tr.insertCell(); // filled by devRender()
if (pIsSFP[i-1]) {
tr.insertCell(); tr.insertCell(); tr.insertCell();
continue;
}
td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i);
td = tr.insertCell(); td.innerHTML = dSwitch.replaceAll("disable_port", "disable_port_" + i)
.replace("portOnOff()", "portOnOff(" + i + ")");
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="applySpeed(' + i + ');">' + t('port_apply') + '</button>';
td = tr.insertCell();
td.innerHTML = button;
}
}
tbl = document.getElementById('mtutable');
if (tbl.rows.length <= 2 && numPorts) {
const mSelect = '<select name="mtu_sel" id="mtu_sel">'
+ '<option value="16383">16383</option>'
+ '<option value="1522">1522</option>'
+ '<option value="1536">1536</option>'
+ '<option value="1552">1552</option>'
+ '<option value="9216">9216</option>'
+ '</select>';
var tr = tbl.insertRow();
for (let i = 1; i <= numPorts; i++) {
let td = tr.insertCell();
if (pIsSFP[i-1])
td.innerHTML = '<object type="image/svg+xml" data="sfp.svg" width="60"></object>'
else
td.innerHTML = '<object type="image/svg+xml" data="port.svg" width="40"></object>'
}
tr = tbl.insertRow();
for (let i = 1; i <= numPorts; i++) {
let td = tr.insertCell();
td.innerHTML = mSelect.replaceAll("mtu_sel", "mtu_sel_" + i);
}
tr = tbl.insertRow();
for (let i = 1; i <= numPorts; i++) {
let td = tr.insertCell();
td.innerHTML = '<button type="button" style="margin: 0 0 0 24px" onclick="applyMTU(' + i + ');">' + t('port_apply') + '</button>';
}
}
}
function updatePortTable() {
console.log("updatePortTable called");
var tbl = document.getElementById('speedtable');
if (tbl.rows.length <= 2 || !numPorts)
return;
for (let i = 1; i <= numPorts ; i++) {
tbl.rows[i].cells[2].innerHTML = linkText(pState[i-1]+1);
if (pIsSFP[i-1])
continue;
if (!clicked[i] && pState[i - 1] < 0) {
document.getElementById('speed_sel_' + i).disabled = true;
document.getElementById('disable_port_' + i).checked = true;
}
}
}
async function applySpeed(port) {
var speed = document.getElementById('speed_sel_' + port).value;
var disabled = document.getElementById('disable_port_' + port).checked;
var cmd = "port " + port + " ";
if (!disabled)
cmd = cmd + speed;
else
cmd = cmd + "off";
console.log("CMD: " + cmd);
try {
const response = await fetch('/cmd', {
method: 'POST',
body: cmd
});
console.log('Completed!', response);
} catch(err) {
console.error(`Error: ${err}`);
}
}
async function portOnOff(p) {
var disabled = document.getElementById('disable_port_' + p).checked;
document.getElementById('speed_sel_' + p).disabled = disabled;
clicked[p] = 1;
}
async function applyMTU(port) {
var mtu = document.getElementById('mtu_sel_' + port).value;
var cmd = "mtu " + port + " " + mtu;
try {
const response = await fetch('/cmd', {
method: 'POST',
body: cmd
});
console.log('MTU Completed!', response);
getMTUs();
} catch(err) {
console.error(`Error: ${err}`);
}
}
function devRender(entries) {
var tbl = document.getElementById('speedtable');
if (tbl.rows.length <= 2 || !numPorts)
return;
var perPort = {};
for (var i = 0; i < entries.length; i++) {
var e = entries[i];
if (e.port == 'CPU')
continue;
if (!perPort[e.port])
perPort[e.port] = [];
if (perPort[e.port].indexOf(e.mac) < 0)
perPort[e.port].push(e.mac);
}
for (let i = 1; i <= numPorts; i++) {
var cell = tbl.rows[i].cells[3];
var macs = perPort[i] || [];
if (macs.length == 1) {
cell.textContent = macs[0];
cell.title = '';
} else if (macs.length > 1) {
cell.textContent = macs.length + ' ' + t('port_devices');
cell.title = macs.join('\n');
} else {
cell.textContent = '';
cell.title = '';
}
}
}
function devWalk() {
walkL2(function(entries, ok) {
if (ok)
devRender(entries);
setTimeout(devWalk, 15000);
});
}
function getMTUs() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
const s = JSON.parse(xhttp.responseText);
console.log("MTUS: ", JSON.stringify(s));
for (let i = 0; i < s.length; i++) {
p = s[i];
let n = p.portNum;
mtus[n] = parseInt(p.mtu, 16);
var mtu = document.getElementById('mtu_sel_' + n);
if (!mtu)
continue;
mtu.value = mtus[n];
}
}
};
xhttp.open("GET", "/mtu.json", true);
xhttp.timeout = 1500; sendXHTTP(xhttp);
}
window.addEventListener("load", function() {
update( () => {
createPortTable();
updatePortTable();
getMTUs()
setTimeout(devWalk, 3000);
const interval = setInterval(update, 2000);
const updatePortTableInterval = setInterval(updatePortTable, 1000);
});
});