diff --git a/html/stat.html b/html/stat.html
index 5cfaf05..cb5cbfe 100644
--- a/html/stat.html
+++ b/html/stat.html
@@ -3,14 +3,42 @@
FreeSwitchOS Port Statistics
+
+
Port Statistics
- | Port | link | TX Good | TX Bad | RX Good | RX Bad |
+ | Port | link | TX Good | TX Bad | RX Good | RX Bad | All Counters |
diff --git a/html/stat.js b/html/stat.js
index 31973fc..6d1618b 100644
--- a/html/stat.js
+++ b/html/stat.js
@@ -1,3 +1,160 @@
+const mib_counters = [
+ "Interface in Octets", 8,
+ "", 0,
+ "Interface out Octets", 8,
+ "", 0,
+ "Interface in Unicast Pkts", 8,
+ "", 0,
+ "Interface in Multicast Pkts", 8,
+ "", 0,
+ "Interface in Broadcast Pkts", 8,
+ "", 0,
+ "Interface out Unicast Pkts", 8, // 10
+ "", 0,
+ "Interface out Multicast Pkts", 8,
+ "", 0,
+ "Interface out Broadcast Pkts", 8,
+ "", 0,
+ "Interface out discards", 4,
+ "802.1d Tp Port in discards", 4,
+ "802.3 Single collision frames", 4,
+ "802.3 Multi collision frames", 4,
+ "802.3 Deferred transmissions", 4, // 20
+ "802.3 Late collisions", 4,
+ "802.3 Excessive collisions", 4,
+ "802.3 Symbol errors", 4,
+ "802.3 Control in unknown opcodes", 4,
+ "802.3 In Pause frames", 4,
+ "802.3 Out Pause frames", 4,
+ "Ether drop events", 4,
+ "TX Ether Broadcast Pkts", 4,
+ "TX Ether Multicast Pkts", 4,
+ "TX Ether CRC Align errors", 4, // 30
+ "RX Ether CRC Align errors", 4,
+ "TX Ether Undersized Pkts", 4,
+ "RX Ether Undersized Pkts", 4,
+ "TX Ether Oversized Pkts", 4,
+ "RX Ether Oversized Pkts", 4,
+ "TX Ether Fragments", 4,
+ "RX Ether fragments", 4,
+ "TX Ether Jabbers", 4,
+ "RX Ether Jabbers", 4,
+ "TX Ether Collisions", 4, // 40
+ "TX Ether Pkts 640 Octets", 4,
+ "RX Ether Pkts 640 Octets", 4,
+ "TX Ether 65-127 Octets", 4,
+ "RX Ether 65-127 Octets", 4,
+ "TX Ether Pkts 128-255 Octets", 4,
+ "RX Ether Pkts 128-255 Octets", 4,
+ "TX Ether Pkts 256-511 Octets", 4,
+ "RX Ether Pkts 256-511 Octets", 4,
+ "TX Ether Pkts 512-1023 Octets", 4,
+ "RX Ether Pkts 512-1023 Octets", 4, // 50
+ "TX Ether Pkts 1024-1518 Octets", 4,
+ "RX Ether Pkts 1024-1518 Octets", 4,
+ "", 4,
+ "RX Ether Undersized Drop Pkts", 4, // 54
+ "TX Ether Pkts >1518 Octets", 4,
+ "RX Ether Pkts >1518 Octets", 4,
+ "TX Ether Pkts too large", 4,
+ "RX Ether Pkts too large", 4,
+ "TX Ether Flexible Octets Set 1", 4,
+ "RX Ether Flexible Octets Set 1", 4,// 60
+ "TX Ether Flexible Octets CRC Set 1", 4,
+ "RX Ether Flexible Octets CRC Set 1", 4,
+ "TX Ether Flexible Octets Set 0", 4,
+ "RX Ether Flexible Octets Set 0", 4,
+ "TX Ether Flexible Octets CRC Set 0", 4,
+ "RX Ether Flexible Octets CRC Set 0", 4,
+ "Lenth Field Errors", 4,
+ "False Carriers", 4,
+ "Undersized Octets", 4,
+ "Framing Errors", 4, // 70
+ "", 4,
+ "RX MAC Discards", 4, // 72
+ "RX MAC IPG Short Drop", 4,
+ "", 4,
+ "802.1d TP Learned Entry Discards", 4, // 75
+ "Egress Queue 7 Dropped Pkts", 4,
+ "Egress Queue 6 Dropped Pkts", 4,
+ "Egress Queue 5 Dropped Pkts", 4,
+ "Egress Queue 4 Dropped Pkts", 4,
+ "Egress Queue 3 Dropped Pkts", 4, // 80
+ "Egress Queue 2 Dropped Pkts", 4,
+ "Egress Queue 1 Dropped Pkts", 4,
+ "Egress Queue 0 Dropped Pkts", 4,
+ "Egress Queue 7 Out Pkts", 4,
+ "Egress Queue 6 Out Pkts", 4,
+ "Egress Queue 5 Out Pkts", 4,
+ "Egress Queue 4 Out Pkts", 4,
+ "Egress Queue 3 Out Pkts", 4,
+ "Egress Queue 2 Out Pkts", 4,
+ "Egress Queue 1 Out Pkts", 4, // 90
+ "Egress Queue 0 Out Pkts", 4,
+ "TX Good Counter", 8,
+ "", 0,
+ "RX Good Counter", 8,
+ "", 0,
+ "RX Error Counter", 4,
+ "TX Error Counter", 4,
+ "TX Good Counter PHY", 8,
+ "", 0,
+ "RX Good Counter PHY", 8, // 100
+ "", 0,
+ "RX Error Counter PHY", 4,
+ "TX Error Counter PHY", 4
+];
+
+
+function getCounters(port) {
+ var xhttp = new XMLHttpRequest();
+ const popup = document.getElementById('popup');
+ xhttp.onreadystatechange = function() {
+ if (this.readyState == 4 && this.status == 200) {
+ const s = JSON.parse(xhttp.responseText);
+ console.log("Counters: ", JSON.stringify(s));
+ const ptext = document.getElementById('popup_text');
+ var t = " | Counter | Value | Counter | Value |
";
+ console.log("Counter 0: ", BigInt(s[0]).toString(), " length: ", s.length);
+ var c = 0;
+ for (i = 0; i < mib_counters.length; i += 4) {
+ console.log(i, " ", mib_counters[i], ": ", mib_counters[i+1]);
+ if (mib_counters[i] == "" && mib_counters[i + 1] == 8) {
+ console.log("c " + i + ": continue");
+ continue;
+ }
+ var count = BigInt(s[i/4]);
+ if (mib_counters[i+1] == 8) {
+ t += "| " + mib_counters[i] + " | " + count.toString() + " | ";
+ c += 1;
+ } else if (mib_counters[i+1] == 4) {
+ if (mib_counters[i] != "") {
+ t += "" + mib_counters[i] + " | " + (count >> 32n).toString() + " | ";
+ c += 1;
+ }
+ if (c == 2) {
+ t += "
";
+ c = 0;
+ }
+ if (mib_counters[i+2] != "") {
+ t += "| " + mib_counters[i+2] + " | " + (count & 4294967295n).toString() + " | ";
+ c += 1;
+ }
+ }
+ if (c == 2) {
+ t += "
";
+ c = 0;
+ }
+ }
+ ptext.innerHTML = t + "
";
+ popup.style.display = 'flex';
+ }
+ };
+ xhttp.open("GET", "/counters.json?port=" + port, true);
+ xhttp.timeout = 1500; xhttp.send();
+}
+
+
function fillStats() {
var tbl = document.getElementById('statstable');
if (!numPorts)
@@ -21,8 +178,21 @@ function fillStats() {
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`));
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]} pkts`));
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]} pkts`));
+ var button = '';
+ td = tr.insertCell(); td.innerHTML = button;
}
}
}
const stat = setInterval(fillStats, 1000);
+
+const popup = document.getElementById('popup');
+const closePopup = document.getElementById('closePopup');
+closePopup.addEventListener('click', () => {
+ popup.style.display = 'none';
+});
+window.addEventListener('click', (event) => {
+ if (event.target === popup) {
+ popup.style.display = 'none';
+ }
+});
diff --git a/httpd/httpd.c b/httpd/httpd.c
index 0d2fe5b..b50a3e7 100644
--- a/httpd/httpd.c
+++ b/httpd/httpd.c
@@ -570,7 +570,7 @@ void httpd_appcall(void)
parse_short(q + 15);
send_vlan(short_parsed);
} else if (is_word(q, "/counters.json")) {
- send_counters(q[19]-'0');
+ send_counters(q[20]-'0');
} else if (is_word(q, "/eee.json")) {
send_eee();
} else if (is_word(q, "/mirror.json")) {
diff --git a/httpd/page_impl.c b/httpd/page_impl.c
index 2b5807b..871818d 100644
--- a/httpd/page_impl.c
+++ b/httpd/page_impl.c
@@ -143,6 +143,16 @@ void reg_to_html(register uint16_t reg)
}
+void reg_to_html_long(register uint16_t reg)
+{
+ reg_read_m(reg);
+ byte_to_html(sfr_data[0]);
+ byte_to_html(sfr_data[1]);
+ byte_to_html(sfr_data[2]);
+ byte_to_html(sfr_data[3]);
+}
+
+
void send_sfp_info(uint8_t sfp)
{
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
@@ -257,21 +267,19 @@ void send_counters(char port)
dbg_string("send_counters called: "); dbg_byte(port); dbg_char('\n');
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
dbg_string("sending counters\n");
-
- port--;
+ dbg_byte(port);
uint8_t i = machine.phys_to_log_port[port];
- slen += strtox(outbuf + slen, "{\"portNum\":");
- itoa_html(i + 1);
- for (uint8_t j = 0; j < 0x3f; j++) {
- STAT_GET(j, i);
- slen += strtox(outbuf + slen, ",\"cnt_");
- itoa_html(j);
- slen += strtox(outbuf + slen, "\":\"0x");
+ slen += strtox(outbuf + slen, "[");
+ for (uint8_t counter = 0; counter < 0x37; counter++) {
+ STAT_GET(counter, i);
+ slen += strtox(outbuf + slen, "\"0x");
reg_to_html(RTL837X_STAT_V_HIGH);
- reg_to_html(RTL837X_STAT_V_LOW);
+ reg_to_html_long(RTL837X_STAT_V_LOW);
char_to_html('\"');
+ if (counter != 0x36)
+ char_to_html(',');
}
- char_to_html('}');
+ char_to_html(']');
}
diff --git a/rtl837x_common.h b/rtl837x_common.h
index ef8d4d6..57c0e6a 100644
--- a/rtl837x_common.h
+++ b/rtl837x_common.h
@@ -36,8 +36,21 @@
// the RTL_FRAME_TAG_ID is used as part of an 8-byte tag. When VLAN is activated,
// the VLAN tag is inserted after the RTL tag
// See here for the RTL tag: https://github.com/torvalds/linux/commit/1521d5adfc2b557e15f97283c8b7ad688c3ebc40
-#define RTL_TAG_SIZE 8
-#define VLAN_TAG_SIZE 4
+struct rtl_tag {
+ uint16_t tag; // This is 0x8899 for the RTL837X
+ uint8_t version; // Version is 4
+ uint8_t reason;
+ uint16_t flags;
+ uint16_t pmask; // A bit mask for a TX pkt, 4-bit port-number for RX
+};
+
+struct vlan_tag {
+ uint16_t svlan; // Service VLAN
+ uint16_t vlan;
+};
+
+#define RTL_TAG_SIZE (sizeof (struct rtl_tag))
+#define VLAN_TAG_SIZE (sizeof (struct vlan_tag))
#define RTL_FRAME_TAG_ID 0x8899
// For RX and TX, an 8 byte header describing the frame to be moved to the Asic
@@ -70,15 +83,6 @@ struct flash_region_t {
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
-// 8899 04 0000 20 0004
-struct rtl_tag {
- uint16_t tag;
- uint8_t version;
- uint8_t reason;
- uint16_t flags;
- uint16_t pmask; // A bit mask for a TX pkt, 4-bit port-number for RX
-};
-
// Headers for calls in the common code area (HOME/BANK0)
void print_string(__code char *p);
void print_long(__xdata uint32_t a);
diff --git a/rtl837x_port.c b/rtl837x_port.c
index bb96983..08f653c 100644
--- a/rtl837x_port.c
+++ b/rtl837x_port.c
@@ -400,17 +400,17 @@ void port_stats_print(void) __banked
print_string("Up\t");
break;
}
- STAT_GET(0x2f, i);
+ STAT_GET(STAT_COUNTER_TX_PKTS, i);
print_reg(RTL837X_STAT_V_LOW); write_char('\t');
- STAT_GET(0x30, i);
+ STAT_GET(STAT_COUNTER_ERR_PKTS, i);
+ print_reg(RTL837X_STAT_V_LOW); write_char('\t');
+
+ STAT_GET(STAT_COUNTER_RX_PKTS, i);
+ print_reg(RTL837X_STAT_V_LOW); write_char('\t');
+
+ STAT_GET(STAT_COUNTER_ERR_PKTS, i);
print_reg(RTL837X_STAT_V_HIGH); write_char('\t');
-
- STAT_GET(0x2e, i);
- print_reg(RTL837X_STAT_V_LOW); write_char('\t');
-
- STAT_GET(0x30, i);
- print_reg(RTL837X_STAT_V_LOW); write_char('\t');
print_string("\n");
}
}
diff --git a/rtl837x_port.h b/rtl837x_port.h
index e551c11..22ea1dd 100644
--- a/rtl837x_port.h
+++ b/rtl837x_port.h
@@ -3,9 +3,9 @@
#include
-#define STAT_COUNTER_TX_PKTS 0x2e
-#define STAT_COUNTER_RX_PKTS 0x2f
-#define STAT_COUNTER_ERR_PKTS 0x30
+#define STAT_COUNTER_TX_PKTS 46
+#define STAT_COUNTER_RX_PKTS 47
+#define STAT_COUNTER_ERR_PKTS 48
#define STAT_GET(cnt, port) \
REG_WRITE(RTL837X_STAT_GET, 0x00, 0x00, cnt >> 3, (cnt << 5) | (port << 1) | 1); \
diff --git a/rtl837x_regs.h b/rtl837x_regs.h
index 07e5e90..6a43f95 100644
--- a/rtl837x_regs.h
+++ b/rtl837x_regs.h
@@ -93,11 +93,14 @@
*/
#define RTL837X_REG_NIC_BUFFSIZE_TX 0x7844
#define RTL837X_REG_NIC_RXBUFF_RX 0x7848
+#define RTL837X_REG_NIC_RXCMD 0x784c
+#define RTL837X_REG_NIC_TXCMD 0x7850
#define RTL837X_REG_RX_CTRL 0x785c
#define RTL837X_REG_TX_CTRL 0x7860
-#define RTL837X_REG_RX_AVAIL 0x7874
-#define RTL837X_REG_RX_RINGPTR 0x787c
-#define RTL837X_REG_RX_DONE 0x784c
+#define RTL837X_REG_NIC_RX_BUFF_DATA 0x7874
+#define RTL837X_REG_CPU_RX_CURR_PKT 0x787c
+#define RTL837X_REG_NIC_TX_CURR_PKT 0x7884
+#define RTL837X_REG_CPU_TX_CURR_PKT 0x7890
#define RTL837X_REG_CPU_TAG 0x6720
#define RTL837X_REG_CPU_TAG_AWARE_PMASK 0x603C
#define RTL837X_REG_MAC_FORCE_MODE 0x6344
diff --git a/rtlplayground.c b/rtlplayground.c
index b463648..8bc0730 100644
--- a/rtlplayground.c
+++ b/rtlplayground.c
@@ -819,7 +819,7 @@ void tcpip_output(void)
uip_buf[VLAN_TAG_SIZE + 2] = uip_buf[VLAN_TAG_SIZE + 3] = 0;
uip_buf[VLAN_TAG_SIZE + 6] = uip_buf[VLAN_TAG_SIZE + 7] = 0;
- reg_read_m(0x7890);
+ reg_read_m(RTL837X_REG_CPU_TX_CURR_PKT);
uint16_t ring_ptr = ((uint16_t)sfr_data[2]) << 8;
ring_ptr |= sfr_data[3];
@@ -835,20 +835,20 @@ void tcpip_output(void)
// Move data over from xmem buffer to ASIC side using DMA
nic_tx_packet(ring_ptr);
- reg_read_m(0x7884); // actual bytes sent, for now we assume everything worked
+ // New position of the ring-pointer on the NIC-side indicates number of bytes transmitted
+ reg_read_m(RTL837X_REG_NIC_TX_CURR_PKT);
// Do actual TX of data on ASIC side
- sfr_data[0] = sfr_data[1] = sfr_data[2] = 0;
- sfr_data[3] = 0x1;
- reg_write_m(0x7850);
+ REG_SET(RTL837X_REG_NIC_TXCMD, 1);
}
void handle_rx(void)
{
- reg_read_m(RTL837X_REG_RX_AVAIL);
+ // Check the amount of data available on the NIC/ASIC side
+ reg_read_m(RTL837X_REG_NIC_RX_BUFF_DATA);
if (sfr_data[2] != 0 || sfr_data[3] != 0) {
- reg_read_m(RTL837X_REG_RX_RINGPTR);
+ reg_read_m(RTL837X_REG_CPU_RX_CURR_PKT);
uint16_t ring_ptr = ((uint16_t)sfr_data[2]) << 8;
ring_ptr |= sfr_data[3];
ring_ptr <<= 3;
@@ -872,16 +872,13 @@ void handle_rx(void)
write_char(' ');
}
#endif
- sfr_data[0] = sfr_data[1] = sfr_data[2] = 0;
- sfr_data[3] = 0x1;
- reg_write_m(RTL837X_REG_RX_DONE);
+ REG_SET(RTL837X_REG_NIC_RXCMD, 1);
uip_len = (((uint16_t)rx_headers[5]) << 8) | rx_headers[4];
-// write_char('>'); print_byte(uip_buf[ETHERTYPE_OFFSET]); write_char('<');
-// write_char('>'); print_byte(uip_buf[ETHERTYPE_OFFSET + 1]); write_char('<');
- // Check for ARP packet
- rx_packet_vlan = uip_buf[12 + RTL_TAG_SIZE + 2] & 0xf;
+
+ // Retrieve VLAN from VLAN-tag
+ rx_packet_vlan = uip_buf[2 * sizeof (struct uip_eth_addr) + RTL_TAG_SIZE + 2] & 0xf;
rx_packet_vlan <<= 8;
- rx_packet_vlan |= uip_buf[12 + RTL_TAG_SIZE + 3];
+ rx_packet_vlan |= uip_buf[2 * sizeof (struct uip_eth_addr) + RTL_TAG_SIZE + 3];
#ifdef RXTXDBG
print_string(" RX-VLAN: "); print_short(rx_packet_vlan); write_char('\n');
print_string(" RX dst: "); print_byte(uip_buf[0]); print_byte(uip_buf[1]); print_byte(uip_buf[2]);
diff --git a/tools/httpd_sim.c b/tools/httpd_sim.c
index 1b9f5ac..b2924dd 100644
--- a/tools/httpd_sim.c
+++ b/tools/httpd_sim.c
@@ -18,6 +18,8 @@
#define PORTS 9
#define NSFP 1
+#define N_COUNTERS 52
+
#if PORTS == 9
const uint8_t physToLogPort[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
#else
@@ -28,7 +30,7 @@ time_t last_called;
time_t last_session_use;
uint64_t txG[PORTS], txB[PORTS], rxG[PORTS], rxB[PORTS];
-char txG_buff[20], txB_buff[20], rxG_buff[20], rxB_buff[20];
+char txG_buff[20], txB_buff[20], rxG_buff[20], rxB_buff[20], counter_buf[20], counter_name[20];
char sfp_temp[8], sfp_vcc[8], sfp_txbias[8], sfp_txpower[8], sfp_rxpower[8], sfp_laser[8], sfp_options[6];
char num_buff[20];
char upload_buffer[4194304]; // 4MB
@@ -199,6 +201,29 @@ void send_status(int s)
}
+void send_counters(int s, int port)
+{
+ struct json_object *v, *counters;
+ const char *jstring;
+ char *header = "HTTP/1.1 200 OK\r\n"
+ "Cache-Control: no-cache\r\n"
+ "Content-Type: application/json; charset=UTF-8\r\n\r\n";
+
+ printf("Sending counters\n");
+ counters = json_object_new_array_ext(N_COUNTERS);
+
+ for (int i = 0; i < N_COUNTERS; i++) {
+ v = json_object_new_object();
+ sprintf(counter_buf, "0x%016lx", 0x1234UL + i);
+ json_object_array_add(counters, json_object_new_string(counter_buf));
+ }
+ write(s, header, strlen(header));
+ jstring = json_object_to_json_string_ext(counters, JSON_C_TO_STRING_PLAIN);
+ write(s, jstring, strlen(jstring));
+ json_object_put(counters);
+}
+
+
void send_eee(int s)
{
struct json_object *ports, *v;
@@ -547,6 +572,14 @@ void launch(struct Server *server)
else
send_config(new_socket);
goto done;
+ } else if (!strncmp(&buffer[4], "/counters.json?port=", 20)) {
+ int port = atoi(&buffer[24]);
+ printf("Counters request for %d\n", port);
+ if (!authenticated)
+ send_unauthorized(new_socket);
+ else
+ send_counters(new_socket, port);
+ goto done;
}
if (!authenticated && !(!strncmp(&buffer[4], "/login.html", 11) || !strncmp(&buffer[4], "/style.css", 10))) {
send_to_login(new_socket);