Merge pull request #150 from logicog/bandwidth_web

Bandwidth web
This commit is contained in:
René van Dorst
2026-03-09 19:54:31 +00:00
committed by GitHub
10 changed files with 290 additions and 4 deletions
+9 -1
View File
@@ -150,6 +150,14 @@ uint8_t atoi_hex(uint8_t idx)
h_idx++; h_idx++;
} }
if (h_idx & 1) {
hexvalue[h_idx >> 1] <<= 4;
hexvalue[3] = hexvalue[3] >> 4 | (hexvalue[2] << 4);
hexvalue[2] = hexvalue[2] >> 4 | (hexvalue[1] << 4);
hexvalue[1] = hexvalue[1] >> 4 | (hexvalue[0] << 4);
hexvalue[0] >>= 4;
}
return ((h_idx + 1) >> 1); return ((h_idx + 1) >> 1);
} }
@@ -707,7 +715,7 @@ void parse_bw(void)
goto err; goto err;
port = cmd_buffer[cmd_words_b[2]] - '1'; port = cmd_buffer[cmd_words_b[2]] - '1';
if (port < 0 || port > 9) if (port > 9)
goto err; goto err;
port = machine.phys_to_log_port[port]; port = machine.phys_to_log_port[port];
+20
View File
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<script src="/main.js"></script>
<link rel="stylesheet" href="style.css">
<title>Ingress and Egress Bandwidth</title>
</head>
<body>
<nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div>
<h1>Ingress and Egress Bandwidth</h1>
<table id="bwtable">
<tr> <th> </th> <th colspan="3"> Ingress </th> <th colspan="2">Egress</th> <th></th></tr>
<tr> <th>Port</th> <th>Limit</th> <th>Bandwidth [kBit/s]</th> <th>Flow Control</th> <th>Limit</th> <th>Bandwidth [kBit/s]</th> <th>Apply</th></tr>
</table>
<script src="/bandwidth.js"></script>
</div>
<script src="/navigation.js"></script>
</body>
</html>
+136
View File
@@ -0,0 +1,136 @@
const iLayout = '" type="number" maxlength="10" size="10" onfocus="inputFocus(';
function createBW() {
var tbl = document.getElementById('bwtable');
const limit = '<input type="checkbox" id="limit_port" onchange="exec();">'
if (tbl.rows.length <= 2 && numPorts) {
clearInterval(createBWInterval);
console.log("CREATING TABLE ", tbl.rows.length);
for (let i = 2; i < 2 + numPorts; i++) {
const tr = tbl.insertRow();
let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i-1}`));
td = tr.insertCell();
td.innerHTML = limit.replaceAll("limit_port", "ilimit_port_" + i).replace("exec()", "iClicked(" + i + ")");
td = tr.insertCell();
td.innerHTML = 'UNLIMITED';
td = tr.insertCell();
td.innerHTML = limit.replaceAll("limit_port", "fc_port_" + i).replace("exec()", "document.getElementById('bwapply_" + i + "').disabled=false;");
td = tr.insertCell();
td.innerHTML = limit.replaceAll("limit_port", "elimit_port_" + i).replace("exec()", "eClicked(" + i + ")");
td = tr.insertCell();
td.innerHTML = 'UNLIMITED';
var button = '<button type="button" id="bwapply_' + i + '" style="margin: 0 0 0 24px" onclick="applyBandwidth(' + i + ');">Apply</button>';
td = tr.insertCell();
td.innerHTML = button;
document.getElementById("bwapply_" + i).disabled = true;
}
}
}
function iClicked(i)
{
document.getElementById("bwapply_" + i).disabled=false;
var tbl = document.getElementById('bwtable');
var tr = tbl.rows[i];
if (!document.getElementById("ilimit_port_" + i).checked) {
tr.cells[2].innerHTML = "UNLIMITED";
document.getElementById("fc_port_" + i).disabled = true;
document.getElementById("fc_port_" + i).checked = true;
} else {
tr.cells[2].innerHTML = '<input id="ibw_' + i + iLayout + i + ')" value="0"/>';
document.getElementById("fc_port_" + i).disabled = false;
document.getElementById("fc_port_" + i).checked = true;
}
}
function eClicked(i)
{
document.getElementById("bwapply_" + i).disabled=false;
var tbl = document.getElementById('bwtable');
var tr = tbl.rows[i];
if (!document.getElementById("elimit_port_" + i).checked) {
tr.cells[5].innerHTML = "UNLIMITED";
} else {
tr.cells[5].innerHTML = '<input id="ebw_' + i + iLayout + i + ')" value="0"/>';
}
}
function inputFocus(i)
{
document.getElementById("bwapply_" + i).disabled=false;
}
async function doCMD(cmd)
{
console.log("Sending >" + cmd + "<");
try {
const response = await fetch('/cmd', {
method: 'POST',
body: cmd
});
console.log('Completed!', response);
} catch(err) {
console.error(`Error: ${err}`);
}
}
async function applyBandwidth(i) {
var tbl = document.getElementById('bwtable');
var tr = tbl.rows[i];
var cmd = "bw in " + (i-1) + " off";
if (document.getElementById("ilimit_port_" + i).checked)
cmd = 'bw in ' + (i-1) + ' ' + parseInt(document.getElementById("ibw_" + i).value).toString(16).padStart(4, "0");;
doCMD(cmd);
if (document.getElementById("ilimit_port_" + i).checked) {
if (!document.getElementById("fc_port_" + i).checked)
cmd = "bw in " + (i-1) + " drop";
doCMD(cmd);
}
var cmd = "bw out " + (i-1) + " off";
if (document.getElementById("elimit_port_" + i).checked)
cmd = 'bw out ' + (i-1) + ' ' + parseInt(document.getElementById("ebw_" + i).value).toString(16).padStart(4, "0");;
doCMD(cmd);
}
function getBW() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
const s = JSON.parse(xhttp.responseText);
console.log("BW: ", JSON.stringify(s));
var tbl = document.getElementById('bwtable');
if (tbl.rows.length > 2 && numPorts) {
for (let i = 2; i < 2 + numPorts; i++) {
p = s[i-2];
let n = p.portNum;
let tr = tbl.rows[n+1];
if (!document.getElementById("bwapply_" + (n+1)).disabled)
continue;
console.log("Table Update row: " + i + " portNum is " + n + ", pState is " + pState[i-2] + ", row number is " + (n+1));
let iBW = parseInt(p.iBW,16) * 16; let eBW = parseInt(p.eBW,16) * 16;
document.getElementById("ilimit_port_" + (n+1)).checked = p.iLimited;
document.getElementById("elimit_port_" + (n+1)).checked = p.eLimited;
if (!p.iLimited) {
tr.cells[2].innerHTML = "UNLIMITED";
} else {
tr.cells[2].innerHTML = '<input id="ibw_' + (n+1) + iLayout + (n+1) + ')" value="' + iBW +'"/>';
}
if (!p.eLimited) {
tr.cells[5].innerHTML = "UNLIMITED";
} else {
tr.cells[5].innerHTML = '<input id="ebw_' + (n+1) + iLayout + (n+1) + ')" value="' + eBW +'"/>';
}
document.getElementById("fc_port_" + (n+1)).checked = p.iFC==1?true:false;
document.getElementById("fc_port_" + (n+1)).disabled = p.iLimited==1?false:true;
}
}
}
};
xhttp.open("GET", "/bandwidth.json", true);
xhttp.timeout = 1500; xhttp.send();
}
window.addEventListener("load", function() {
getBW();
const iCount = setInterval(getBW, 2000);
});
const createBWInterval = setInterval(createBW, 1010);
+1
View File
@@ -7,5 +7,6 @@ document.getElementById('sidebar').innerHTML =
+ "<li><a href='mirror.html'>Mirroring</a></li>" + "<li><a href='mirror.html'>Mirroring</a></li>"
+ "<li><a href='lag.html'>Link Aggregation</a></li>" + "<li><a href='lag.html'>Link Aggregation</a></li>"
+ "<li><a href='eee.html'>EEE</a></li>" + "<li><a href='eee.html'>EEE</a></li>"
+ "<li><a href='bandwidth.html'>Bandwidth Limits</a></li>"
+ "<li><a href='system.html'>System Settings</a></li>" + "<li><a href='system.html'>System Settings</a></li>"
+ "<li><a href='update.html'>Firmware Update</a></li></ul>"; + "<li><a href='update.html'>Firmware Update</a></li></ul>";
+2
View File
@@ -586,6 +586,8 @@ void httpd_appcall(void)
send_counters(q[20]-'0'); send_counters(q[20]-'0');
} else if (is_word(q, "/eee.json")) { } else if (is_word(q, "/eee.json")) {
send_eee(); send_eee();
} else if (is_word(q, "/bandwidth.json")) {
send_bandwidth();
} else if (is_word(q, "/l2.json")) { } else if (is_word(q, "/l2.json")) {
parse_short(q + 13); // e.g.: /l2.json?idx=10 parse_short(q + 13); // e.g.: /l2.json?idx=10
send_l2(short_parsed); send_l2(short_parsed);
+44
View File
@@ -546,6 +546,50 @@ void send_eee(void)
} }
} }
void send_bandwidth(void)
{
dbg_string("send_bandwidth called\n");
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
char_to_html('[');
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
slen += strtox(outbuf + slen, "{\"portNum\":");
itoa_html(machine.log_to_phys_port[i]);
slen += strtox(outbuf + slen, ",\"iLimited\":");
reg_read_m(RTL837X_IGBW_PORT_CTRL + i * 4);
if (sfr_data[1] & 0x10)
char_to_html('1');
else
char_to_html('0');
slen += strtox(outbuf + slen, ",\"iBW\":\"");
byte_to_html(sfr_data[1] & 0x0f);
byte_to_html(sfr_data[2]);
byte_to_html(sfr_data[3]);
slen += strtox(outbuf + slen, "\",\"iFC\":");
if (reg_bit_test(RTL837X_IGBW_PORT_FC_CTRL, i))
char_to_html('1');
else
char_to_html('0');
reg_read_m(RTL837X_EGBW_PORT_CTRL + i * 1024);
slen += strtox(outbuf + slen, ",\"eLimited\":");
if (sfr_data[1] & 0x10)
char_to_html('1');
else
char_to_html('0');
slen += strtox(outbuf + slen, ",\"eBW\":\"");
byte_to_html(sfr_data[1] & 0x0f);
byte_to_html(sfr_data[2]);
byte_to_html(sfr_data[3]);
char_to_html('"');
char_to_html('}');
if (i < machine.max_port)
char_to_html(',');
else
char_to_html(']');
}
}
void send_mtu(void) void send_mtu(void)
{ {
dbg_string("send_mtu called\n"); dbg_string("send_mtu called\n");
+1
View File
@@ -5,6 +5,7 @@ void send_counters(char port);
void send_status(void); void send_status(void);
void send_vlan(uint16_t vlan); void send_vlan(uint16_t vlan);
void send_basic_info(void); void send_basic_info(void);
void send_bandwidth(void);
void send_eee(void); void send_eee(void);
void send_l2(uint16_t idx); void send_l2(uint16_t idx);
void l2_delete(uint16_t idx); void l2_delete(uint16_t idx);
+1
View File
@@ -122,6 +122,7 @@ void print_reg(uint16_t reg);
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg); uint8_t sfp_read_reg(uint8_t slot, uint8_t reg);
void reg_bit_set(uint16_t reg_addr, char bit); void reg_bit_set(uint16_t reg_addr, char bit);
void reg_bit_clear(uint16_t reg_addr, char bit); void reg_bit_clear(uint16_t reg_addr, char bit);
uint8_t reg_bit_test(uint16_t reg_addr, char bit);
void sfr_mask_data(uint8_t n, uint8_t mask, uint8_t set); void sfr_mask_data(uint8_t n, uint8_t mask, uint8_t set);
void sfr_set_zero(void); void sfr_set_zero(void);
void reset_chip(void); void reset_chip(void);
+17
View File
@@ -457,6 +457,23 @@ void reg_bit_clear(uint16_t reg_addr, char bit)
reg_write_m(reg_addr); reg_write_m(reg_addr);
} }
/*
* This sets a bit in the 32bit wide switch register reg_addr
*/
uint8_t reg_bit_test(uint16_t reg_addr, char bit)
{
uint8_t bit_mask = 1 << (bit & 0x7);
bit >>= 3;
reg_read_m(reg_addr);
bit_mask = bit_mask;
if (sfr_data[3-bit] & bit_mask)
return 1;
return 0;
}
/* /*
* This masks the sfr data fields, first &-ing with ~mask, then setting the bits in set * This masks the sfr data fields, first &-ing with ~mask, then setting the bits in set
*/ */
+59 -3
View File
@@ -15,7 +15,7 @@
#define PASSWORD "1234" #define PASSWORD "1234"
#define SESSION_TIMEOUT 2000 #define SESSION_TIMEOUT 2000
#define PORTS 9 #define PORTS 6
#define NSFP 1 #define NSFP 1
#define N_COUNTERS 52 #define N_COUNTERS 52
@@ -229,7 +229,7 @@ void send_status(int s)
void send_counters(int s, int port) void send_counters(int s, int port)
{ {
struct json_object *v, *counters; struct json_object *counters;
const char *jstring; const char *jstring;
char *header = "HTTP/1.1 200 OK\r\n" char *header = "HTTP/1.1 200 OK\r\n"
"Cache-Control: no-cache\r\n" "Cache-Control: no-cache\r\n"
@@ -239,7 +239,6 @@ void send_counters(int s, int port)
counters = json_object_new_array_ext(N_COUNTERS); counters = json_object_new_array_ext(N_COUNTERS);
for (int i = 0; i < N_COUNTERS; i++) { for (int i = 0; i < N_COUNTERS; i++) {
v = json_object_new_object();
sprintf(counter_buf, "0x%016lx", 0x1234UL + i); sprintf(counter_buf, "0x%016lx", 0x1234UL + i);
json_object_array_add(counters, json_object_new_string(counter_buf)); json_object_array_add(counters, json_object_new_string(counter_buf));
} }
@@ -283,6 +282,56 @@ void send_eee(int s)
} }
void send_bandwidth(int s)
{
struct json_object *ports, *v;
const char *jstring;
uint32_t bw;
int limited, fcEnabled;
char *header = "HTTP/1.1 200 OK\r\n"
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
ports = json_object_new_array_ext(PORTS);
for (int i = 1; i <= PORTS; i++) {
v = json_object_new_object();
json_object_object_add(v, "portNum", json_object_new_int(i));
if (i % 2) {
limited = 1;
fcEnabled = i % 4 ? 1 : 0;
bw = 0x100;
} else {
limited = 0;
fcEnabled = 0;
bw = 0xfffff;
}
char bw_buf[20];
sprintf(bw_buf, "%08x", bw);
json_object_object_add(v, "iLimited", json_object_new_int(limited));
json_object_object_add(v, "iFC", json_object_new_int(fcEnabled));
json_object_object_add(v, "iBW", json_object_new_string(bw_buf));
if (i % 4) {
limited = 1;
bw = 0x1000;
} else {
limited = 0;
bw = 0xfffff;
}
sprintf(bw_buf, "%08x", bw);
json_object_object_add(v, "eLimited", json_object_new_int(limited));
json_object_object_add(v, "eBW", json_object_new_string(bw_buf));
json_object_array_add(ports, v);
}
write(s, header, strlen(header));
jstring = json_object_to_json_string_ext(ports, JSON_C_TO_STRING_PLAIN);
write(s, jstring, strlen(jstring));
json_object_put(ports);
}
void send_mirror(int s) void send_mirror(int s)
{ {
uint16_t mirror_tx, mirror_rx = 0; uint16_t mirror_tx, mirror_rx = 0;
@@ -593,6 +642,13 @@ void launch(struct Server *server)
else else
send_eee(new_socket); send_eee(new_socket);
goto done; goto done;
} else if (!strncmp(&buffer[4], "/bandwidth.json", 15)) {
printf("Bandwidth request\n");
if (!authenticated)
send_unauthorized(new_socket);
else
send_bandwidth(new_socket);
goto done;
} else if (!strncmp(&buffer[4], "/information.json", 17)) { } else if (!strncmp(&buffer[4], "/information.json", 17)) {
printf("Status request\n"); printf("Status request\n");
if (!authenticated) if (!authenticated)